<!DOCTYPE html>
<html dir="ltr" lang="zh">
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<meta content='结构型模式 # 1 代理模式 # 1.1 概述 # 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时，访问对象不适合或者不能直接引用目标对象，代理对象作为访问对象和目标对象之间的中介。
Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成，而动态代理代理类则是在Java运行时动态生成。动态代理又有JDK代理和CGLib代理两种。
1.2 结构 # 代理（Proxy）模式分为三种角色：
抽象主题（Subject）类： 通过接口或抽象类声明真实主题和代理对象实现的业务方法。 真实主题（Real Subject）类： 实现了抽象主题中的具体业务，是代理对象所代表的真实对象，是最终要引用的对象。 代理（Proxy）类 ： 提供了与真实主题相同的接口，其内部含有对真实主题的引用，它可以访问、控制或扩展真实主题的功能。 1.3 案例实现 # 火车站卖票：如果要买火车票的话，需要去火车站买票，坐车到火车站，排队等一系列的操作，显然比较麻烦。而火车站在多个地方都有代售点，我们去代售点买票就方便很多了。这个例子其实就是典型的代理模式，火车站是目标对象，代售点是代理对象。类图如下：
1.3.1 静态代理 # 点击展开 ... //卖票接口 public interface SellTickets { void sell(); } //火车站 火车站具有卖票功能，所以需要实现SellTickets接口 public class TrainStation implements SellTickets { public void sell() { System.out.println("火车站卖票"); } } //代售点 public class ProxyPoint implements SellTickets { private TrainStation station = new TrainStation(); public void sell() { System.' name="description"/>
<meta content="#FFFFFF" name="theme-color"/>
<meta content="light dark" name="color-scheme"/><meta content="" property="og:title"/>
<meta content='结构型模式 # 1 代理模式 # 1.1 概述 # 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时，访问对象不适合或者不能直接引用目标对象，代理对象作为访问对象和目标对象之间的中介。
Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成，而动态代理代理类则是在Java运行时动态生成。动态代理又有JDK代理和CGLib代理两种。
1.2 结构 # 代理（Proxy）模式分为三种角色：
抽象主题（Subject）类： 通过接口或抽象类声明真实主题和代理对象实现的业务方法。 真实主题（Real Subject）类： 实现了抽象主题中的具体业务，是代理对象所代表的真实对象，是最终要引用的对象。 代理（Proxy）类 ： 提供了与真实主题相同的接口，其内部含有对真实主题的引用，它可以访问、控制或扩展真实主题的功能。 1.3 案例实现 # 火车站卖票：如果要买火车票的话，需要去火车站买票，坐车到火车站，排队等一系列的操作，显然比较麻烦。而火车站在多个地方都有代售点，我们去代售点买票就方便很多了。这个例子其实就是典型的代理模式，火车站是目标对象，代售点是代理对象。类图如下：
1.3.1 静态代理 # 点击展开 ... //卖票接口 public interface SellTickets { void sell(); } //火车站 火车站具有卖票功能，所以需要实现SellTickets接口 public class TrainStation implements SellTickets { public void sell() { System.out.println("火车站卖票"); } } //代售点 public class ProxyPoint implements SellTickets { private TrainStation station = new TrainStation(); public void sell() { System.' property="og:description"/>
<meta content="article" property="og:type"/>
<meta content="https://helloputong.gitee.io/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E7%BB%93%E6%9E%84%E5%9E%8B%E6%A8%A1%E5%BC%8F/" property="og:url"/><meta content="notes" property="article:section"/>
<title>结构型模式 | Hello! 噗通 🍀</title>
<link href="/manifest.json" rel="manifest"/>
<link href="/favicon.png" rel="icon" type="image/x-icon"/>
<link crossorigin="anonymous" href="/book.min.a82d7e77ceb134d151c4d7e381eeb30623fbd5a524d58c584d8716ecec0205bd.css" integrity="sha256-qC1+d86xNNFRxNfjge6zBiP71aUk1YxYTYcW7OwCBb0=" rel="stylesheet"/>
<script defer="" src="/flexsearch.min.js"></script>
<script crossorigin="anonymous" defer="" integrity="sha256-+pR/j4Voa/VXQmH38FekcfPx1IEWD5WAkNOJruKNmQk=" src="/zh.search.min.fa947f8f85686bf5574261f7f057a471f3f1d481160f958090d389aee28d9909.js"></script>
<script crossorigin="anonymous" defer="" integrity="sha256-b2+Q/LjrHEnsOJg45rgB0N4ZQwuOUWkC+NdcPIvZhzk=" src="/sw.min.6f6f90fcb8eb1c49ec389838e6b801d0de19430b8e516902f8d75c3c8bd98739.js"></script>
<!--
Made with Book Theme
https://github.com/alex-shpak/hugo-book
-->
</head>
<body dir="ltr">
<input class="hidden toggle" id="menu-control" type="checkbox"/>
<input class="hidden toggle" id="toc-control" type="checkbox"/>
<main class="container flex">
<aside class="book-menu">
<div class="book-menu-content">
<nav>
<h2 class="book-brand">
<a class="flex align-center" href="/"><span>Hello! 噗通 🍀</span>
</a>
</h2>
<div class="book-search">
<input aria-label="Search" data-hotkeys="s/" id="book-search-input" maxlength="64" placeholder="Search" type="text"/>
<div class="book-search-spinner hidden"></div>
<ul id="book-search-results"></ul>
</div>
<ul>
<li class="book-section-flat">
<span>--学习笔记--👇</span>
<ul>
<li>
<input class="toggle" id="section-62161c8b7eae8ea89aee3d6f310b2312" type="checkbox"/>
<label class="flex justify-between" for="section-62161c8b7eae8ea89aee3d6f310b2312">
<a class="" role="button">Android</a>
</label>
<ul>
<li>
<a class="" href="/notes/android/mac%E9%80%9A%E8%BF%87homebrew%E5%AE%89%E8%A3%85java8/">Mac 通过 Homebrew 安装 Java8</a>
</li>
<li>
<a class="" href="/notes/android/%E6%B4%BB%E5%8A%A8%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/">活动的生命周期</a>
</li>
<li>
<a class="" href="/notes/android/%E5%B8%B8%E7%94%A8%E6%8E%A7%E4%BB%B6%E5%92%8C4%E7%A7%8D%E5%B8%83%E5%B1%80/">常用控件和4种布局</a>
</li>
<li>
<a class="" href="/notes/android/android-%E4%B8%AD%E4%BA%8B%E4%BB%B6%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/">Android 中事件学习总结</a>
</li>
<li>
<a class="" href="/notes/android/android-%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%E6%9C%BA%E5%88%B6%E5%92%8C%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1/">Android 中的消息机制和异步任务</a>
</li>
<li>
<a class="" href="/notes/android/listview%E4%B8%AD%E5%85%B3%E4%BA%8E%E6%95%B0%E6%8D%AE%E6%9B%B4%E6%96%B0%E7%9A%84%E4%B8%A4%E4%B8%AA%E9%97%AE%E9%A2%98/">List View中关于数据更新的两个问题</a>
</li>
<li>
<a class="" href="/notes/android/spinner-%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/">Spinner 基本使用</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-d1dc8d9746f5c776e8a82499bbb2e7c6" type="checkbox"/>
<label class="flex justify-between" for="section-d1dc8d9746f5c776e8a82499bbb2e7c6">
<a class="" role="button">BMS</a>
</label>
<ul>
<li>
<a class="" href="/notes/bms/bms-%E7%9B%B8%E5%85%B3%E7%90%86%E8%AE%BA%E5%AD%A6%E4%B9%A0/">BMS 相关概念</a>
</li>
<li>
<a class="" href="/notes/bms/%E6%BC%94%E7%A4%BA%E5%8F%82%E6%95%B0%E8%A7%A3%E8%AF%BB/">功能演示</a>
</li>
<li>
<a class="" href="/notes/bms/%E5%8E%9F%E7%90%86%E5%9B%BE%E8%A7%A3%E8%AF%BB/">原理图解读</a>
</li>
<li>
<a class="" href="/notes/bms/%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/">源码解析</a>
</li>
</ul>
</li>
<li>
<input checked="" class="toggle" id="section-b7444509cb631180897a34f028407c2c" type="checkbox"/>
<label class="flex justify-between" for="section-b7444509cb631180897a34f028407c2c">
<a class="" role="button">设计模式</a>
</label>
<ul>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/uml-%E5%9B%BE/">Uml 图</a>
</li>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99/">设计原则</a>
</li>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E5%88%9B%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/">创建型模式</a>
</li>
<li>
<a class="active" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E7%BB%93%E6%9E%84%E5%9E%8B%E6%A8%A1%E5%BC%8F/">结构型模式</a>
</li>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/">行为型模式</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-4364152b7ab5995d509c0b7b811005c4" type="checkbox"/>
<label class="flex justify-between" for="section-4364152b7ab5995d509c0b7b811005c4">
<a class="" role="button">JVM</a>
</label>
<ul>
<li>
<a class="" href="/notes/jvm/%E4%BB%80%E4%B9%88%E6%98%AF-jvm/">什么是 Jvm</a>
</li>
<li>
<a class="" href="/notes/jvm/%E7%A8%8B%E5%BA%8F%E8%AE%A1%E6%95%B0%E5%99%A8/">程序计数器</a>
</li>
<li>
<a class="" href="/notes/jvm/%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%A0%88/">虚拟机栈</a>
</li>
<li>
<a class="" href="/notes/jvm/%E6%9C%AC%E5%9C%B0%E6%96%B9%E6%B3%95%E6%A0%88-/">本地方法栈</a>
</li>
<li>
<a class="" href="/notes/jvm/%E5%A0%86/">堆</a>
</li>
<li>
<a class="" href="/notes/jvm/%E6%96%B9%E6%B3%95%E5%8C%BA/">方法区</a>
</li>
<li>
<a class="" href="/notes/jvm/%E7%9B%B4%E6%8E%A5%E5%86%85%E5%AD%98/">直接内存</a>
</li>
<li>
<a class="" href="/notes/jvm/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6/">垃圾回收</a>
</li>
<li>
<a class="" href="/notes/jvm/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E5%99%A8/">垃圾回收器</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-61661238f18c0095524962a5d1d6e676" type="checkbox"/>
<label class="flex justify-between" for="section-61661238f18c0095524962a5d1d6e676">
<a class="" role="button">Spring</a>
</label>
<ul>
<li>
<a class="" href="/notes/spring/beanfactory%E4%B8%8Eapplicationcontext/">Bean Factory与 Application Context</a>
</li>
<li>
<a class="" href="/notes/spring/nacos-%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83/">Nacos 配置中心</a>
</li>
<li>
<a class="" href="/notes/spring/open-feign-%E8%BF%9C%E7%A8%8B%E8%B0%83%E7%94%A8%E7%A4%BA%E4%BE%8B/">Open Feign 远程调用示例</a>
</li>
<li>
<a class="" href="/notes/spring/springboot-%E6%95%B4%E5%90%88-mybatis-plus/">Spring Boot 整合 My Batis Plus</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-39abd0d44427d4a54e694a2b3f22d967" type="checkbox"/>
<label class="flex justify-between" for="section-39abd0d44427d4a54e694a2b3f22d967">
<a class="" role="button">TensorFlow</a>
</label>
<ul>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E4%B8%80/">Tensor Flow 笔记（一）</a>
</li>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E4%BA%8C/">Tensor Flow 笔记（二）</a>
</li>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E4%B8%89/">Tensor Flow 笔记（三）</a>
</li>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E5%9B%9B/">Tensor Flow 笔记（四）</a>
</li>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E4%BA%94/">Tensor Flow 笔记（五）</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-e2ca0d138d67d9d3ae55da25ac044829" type="checkbox"/>
<label class="flex justify-between" for="section-e2ca0d138d67d9d3ae55da25ac044829">
<a class="" role="button">Redis</a>
</label>
<ul>
<li>
<a class="" href="/notes/redis/nosql%E6%95%B0%E6%8D%AE%E5%BA%93%E7%AE%80%E4%BB%8B/">No Sql数据库简介</a>
</li>
<li>
<a class="" href="/notes/redis/redis-key/">Redis Key</a>
</li>
<li>
<a class="" href="/notes/redis/redis-string/">Redis String</a>
</li>
<li>
<a class="" href="/notes/redis/redis-list/">Redis List</a>
</li>
<li>
<a class="" href="/notes/redis/redis-set/">Redis Set</a>
</li>
<li>
<a class="" href="/notes/redis/redis-hash/">Redis Hash</a>
</li>
<li>
<a class="" href="/notes/redis/redis-zset/">Redis Zset</a>
</li>
<li>
<a class="" href="/notes/redis/redis-%E5%8F%91%E5%B8%83%E4%B8%8E%E8%AE%A2%E9%98%85/">Redis 发布与订阅</a>
</li>
<li>
<a class="" href="/notes/redis/redis-jedis/">Redis Jedis</a>
</li>
<li>
<a class="" href="/notes/redis/springboot-%E6%95%B4%E5%90%88-redis/">Spring Boot 整合 Redis</a>
</li>
<li>
<a class="" href="/notes/redis/redis-%E4%BA%8B%E5%8A%A1%E5%92%8C%E9%94%81%E6%9C%BA%E5%88%B6/">Redis 事务和锁机制</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-58f730a0b22fcdc7a886db614d77f88c" type="checkbox"/>
<label class="flex justify-between" for="section-58f730a0b22fcdc7a886db614d77f88c">
<a class="" role="button">代码随想录刷题</a>
</label>
<ul>
<li>
<a class="" href="/notes/leetcode/day001-%E7%AC%AC%E4%B8%80%E7%AB%A0%E6%95%B0%E7%BB%84/">Day001 第一章数组</a>
</li>
<li>
<a class="" href="/notes/leetcode/day002-%E7%AC%AC%E4%B8%80%E7%AB%A0%E6%95%B0%E7%BB%84/">Day002 第一章数组</a>
</li>
<li>
<a class="" href="/notes/leetcode/day003-%E7%AC%AC%E4%BA%8C%E7%AB%A0%E9%93%BE%E8%A1%A8/">Day003 第二章链表</a>
</li>
<li>
<a class="" href="/notes/leetcode/day004-%E7%AC%AC%E4%BA%8C%E7%AB%A0%E9%93%BE%E8%A1%A8/">Day004 第二章链表</a>
</li>
<li>
<a class="" href="/notes/leetcode/day006-%E7%AC%AC%E4%B8%89%E7%AB%A0%E5%93%88%E5%B8%8C%E8%A1%A8/">Day006 第三章哈希表</a>
</li>
<li>
<a class="" href="/notes/leetcode/day007-%E7%AC%AC%E4%B8%89%E7%AB%A0%E5%93%88%E5%B8%8C%E8%A1%A8/">Day007 第三章哈希表</a>
</li>
<li>
<a class="" href="/notes/leetcode/day008-%E7%AC%AC%E5%9B%9B%E7%AB%A0%E5%AD%97%E7%AC%A6%E4%B8%B2/">Day008 第四章字符串</a>
</li>
<li>
<a class="" href="/notes/leetcode/day009-%E7%AC%AC%E5%9B%9B%E7%AB%A0%E5%AD%97%E7%AC%A6%E4%B8%B2/">Day009 第四章字符串</a>
</li>
<li>
<a class="" href="/notes/leetcode/day010-%E7%AC%AC%E4%BA%94%E7%AB%A0%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97/">Day010 第五章栈与队列</a>
</li>
<li>
<a class="" href="/notes/leetcode/day011-%E7%AC%AC%E4%BA%94%E7%AB%A0%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97/">Day011 第五章栈与队列</a>
</li>
<li>
<a class="" href="/notes/leetcode/day013-%E7%AC%AC%E4%BA%94%E7%AB%A0%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97/">Day013 第五章栈与队列</a>
</li>
<li>
<a class="" href="/notes/leetcode/day014-%E7%AC%AC%E5%85%AD%E7%AB%A0%E4%BA%8C%E5%8F%89%E6%A0%91/">Day014 第六章二叉树</a>
</li>
<li>
<a class="" href="/notes/leetcode/day015-%E7%AC%AC%E5%85%AD%E7%AB%A0%E4%BA%8C%E5%8F%89%E6%A0%91/">Day015 第六章二叉树</a>
</li>
<li>
<a class="" href="/notes/leetcode/day017-%E7%AC%AC%E5%85%AD%E7%AB%A0%E4%BA%8C%E5%8F%89%E6%A0%91/">Day017 第六章二叉树</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-4f95435d3a74007e2c985ea455bbb6e6" type="checkbox"/>
<label class="flex justify-between" for="section-4f95435d3a74007e2c985ea455bbb6e6">
<a class="" role="button">MyBatisPlus</a>
</label>
<ul>
<li>
<a class="" href="/notes/mybatisplus/%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/">MP快速入门</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E4%B8%80%E8%88%AC%E6%9F%A5%E8%AF%A2%E6%93%8D%E4%BD%9C/">一般查询操作</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E5%88%86%E9%A1%B5%E6%9F%A5%E8%AF%A2/">分页查询</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4/">逻辑删除</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E6%9D%A1%E4%BB%B6%E6%9F%A5%E8%AF%A2/">条件查询</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E5%B0%81%E8%A3%85service%E4%BD%BF%E7%94%A8/">封装service使用</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-3907b2cf55ed520ad784e24525c8baa4" type="checkbox"/>
<label class="flex justify-between" for="section-3907b2cf55ed520ad784e24525c8baa4">
<a class="" role="button">Swift</a>
</label>
<ul>
<li>
<a class="" href="/notes/swift/swiftui-%E5%B8%B8%E7%94%A8%E8%A7%86%E5%9B%BE-views/">Swift Ui 常用视图 Views</a>
</li>
<li>
<a class="" href="/notes/swift/swiftui-%E4%BF%A1%E6%81%AF%E8%A7%86%E5%9B%BE-views/">Swift Ui 信息视图 Views</a>
</li>
<li>
<a class="" href="/notes/swift/swiftui-%E5%B1%82%E7%BA%A7%E8%A7%86%E5%9B%BE-views/">Swift Ui 层级视图 Views</a>
</li>
<li>
<a class="" href="/notes/swift/swiftui-%E6%8E%A7%E5%88%B6%E8%A7%86%E5%9B%BE-views/">Swift Ui 控制视图 Views</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-0f70934a6e5284fbc93928c61dfe9c83" type="checkbox"/>
<label class="flex justify-between" for="section-0f70934a6e5284fbc93928c61dfe9c83">
<a class="" role="button">Java</a>
</label>
<ul>
<li>
<a class="" href="/notes/java/arraylist-%E6%89%A9%E5%AE%B9%E8%A7%84%E5%88%99/">Array List 扩容规则</a>
</li>
<li>
<a class="" href="/notes/java/hashmap-%E7%9B%B8%E5%85%B3%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/">Hash Map 相关学习总结</a>
</li>
<li>
<a class="" href="/notes/java/java-%E5%8F%8D%E5%B0%84/">Java 反射</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-3d1ea9814960db7e996773b67773e705" type="checkbox"/>
<label class="flex justify-between" for="section-3d1ea9814960db7e996773b67773e705">
<a class="" role="button">Java八股</a>
</label>
<ul>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/%E5%B9%B6%E5%8F%91/">Concurrence</a>
</li>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/mybatis/">MyBatis</a>
</li>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/mysql/">MySQL</a>
</li>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/jvm/">Jvm</a>
</li>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/redis/">Redis</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-ea55243c547fa272027885b73a74852e" type="checkbox"/>
<label class="flex justify-between" for="section-ea55243c547fa272027885b73a74852e">
<a class="" role="button">嵌入式重点总结</a>
</label>
<ul>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/c/">C 语言相关</a>
</li>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/%E4%B8%AD%E6%96%AD%E7%B3%BB%E7%BB%9F/">中断系统</a>
</li>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/%E5%AE%9A%E6%97%B6%E5%99%A8/">TIM</a>
</li>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/adc/">ADC</a>
</li>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98/">嵌入式知识点串烧</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="book-section-flat">
<span>--解决方案--👇</span>
<ul>
<li>
<input class="toggle" id="section-f1d4602254471b9d0da445dd468cd456" type="checkbox"/>
<label class="flex justify-between" for="section-f1d4602254471b9d0da445dd468cd456">
<a class="" role="button">环境配置</a>
</label>
<ul>
<li>
<a class="" href="/solution/environment/apple-m%E7%B3%BB%E5%88%97%E8%8A%AF%E7%89%87%E5%AE%89%E8%A3%85-pyqt/">Apple M系列芯片安装 Pyqt</a>
</li>
<li>
<a class="" href="/solution/environment/docker-%E5%AE%89%E8%A3%85-redis-/">Docker 安装 Redis</a>
</li>
<li>
<a class="" href="/solution/environment/hugo-%E4%B8%BB%E9%A2%98-hugo-book-%E4%B8%AD%E8%8B%B1%E6%96%87%E6%90%9C%E7%B4%A2%E9%85%8D%E7%BD%AE/">Hugo 主题 Hugo Book 中英文搜索配置</a>
</li>
<li>
<a class="" href="/solution/environment/iterm2-oh-my-zsh-%E9%85%8D%E7%BD%AE/">I Term2 Oh My Zsh 配置</a>
</li>
<li>
<a class="" href="/solution/environment/m1-%E8%8A%AF%E7%89%87-docker-%E5%AE%89%E8%A3%85-mysql5.7-/">M1 芯片 Docker 安装 Mysql5.7</a>
</li>
<li>
<a class="" href="/solution/environment/mac-idea-%E5%BF%AB%E6%8D%B7%E9%94%AE%E4%BD%8D/">MAC Idea 快捷键位</a>
</li>
<li>
<a class="" href="/solution/environment/mac-%E5%90%AF%E5%8A%A8%E5%8F%B0%E8%87%AA%E5%AE%9A%E4%B9%89%E8%A1%8C%E5%88%97%E5%B8%83%E5%B1%80/">MAC 启动台自定义行列布局</a>
</li>
<li>
<a class="" href="/solution/environment/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/">内网穿透</a>
</li>
<li>
<a class="" href="/solution/environment/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E7%9A%84%E8%87%AA%E5%90%AF%E5%8A%A8%E8%AE%BE%E7%BD%AE/">内网穿透的自启动设置</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-5a76a664ba4855b79d3c1bc77e5b08b1" type="checkbox"/>
<label class="flex justify-between" for="section-5a76a664ba4855b79d3c1bc77e5b08b1">
<a class="" role="button">杂乱问题</a>
</label>
<ul>
<li>
<a class="" href="/solution/problems/brew-%E4%B8%80%E4%BA%9B%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/">Brew 一些常用命令</a>
</li>
<li>
<a class="" href="/solution/problems/docker-%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/">Docker 常用命令</a>
</li>
<li>
<a class="" href="/solution/problems/git-github-%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4%E6%95%B4%E7%90%86/">Git Git Hub 相关命令整理</a>
</li>
<li>
<a class="" href="/solution/problems/%E9%9D%A2%E8%AF%95%E9%A2%98%E6%89%AB%E7%9B%B2/">面试题扫盲</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="book-section-flat">
<span>一点业余👇</span>
<ul>
</ul>
</li>
<li class="book-section-flat">
<span>--其他记录--👇</span>
<ul>
<li>
<input class="toggle" id="section-9ef4d2063ddc9af7785b193647f22260" type="checkbox"/>
<label class="flex justify-between" for="section-9ef4d2063ddc9af7785b193647f22260">
<a class="" role="button">我和阿刁</a>
</label>
<ul>
<li>
<a class="" href="/daily/ad/%E5%85%B3%E4%BA%8E%E9%98%BF%E5%88%812022%E5%B9%B4%E7%9A%84%E7%94%9F%E6%97%A5%E7%9A%84%E5%B0%8F%E8%AE%BA%E6%96%87/">关于阿刁2022年的生日的小论文</a>
</li>
<li>
<a class="" href="/daily/ad/%E5%85%B3%E4%BA%8E%E9%98%BF%E5%88%81%E7%9A%842021%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93/">关于阿刁的2021年度总结</a>
</li>
<li>
<a class="" href="/daily/ad/%E5%85%B3%E4%BA%8E%E9%98%BF%E5%88%81%E7%9A%842022%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93/">关于阿刁的2022年度总结</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
<script>(function(){var e=document.querySelector("aside .book-menu-content");addEventListener("beforeunload",function(){localStorage.setItem("menu.scrollTop",e.scrollTop)}),e.scrollTop=localStorage.getItem("menu.scrollTop")})()</script>
</div>
</aside>
<div class="book-page">
<header class="book-header">
<div class="flex align-center justify-between">
<label for="menu-control">
<img alt="Menu" class="book-icon" src="/svg/menu.svg"/>
</label>
<strong>结构型模式</strong>
<label for="toc-control">
<img alt="Table of Contents" class="book-icon" src="/svg/toc.svg"/>
</label>
</div>
<aside class="hidden clearfix">
<nav id="TableOfContents">
<ul>
<li><a href="#结构型模式">结构型模式</a>
<ul>
<li><a href="#1-代理模式">1 代理模式</a>
<ul>
<li><a href="#11-概述">1.1 概述</a></li>
<li><a href="#12-结构">1.2 结构</a></li>
<li><a href="#13-案例实现">1.3 案例实现</a>
<ul>
<li><a href="#131-静态代理">1.3.1 静态代理</a></li>
<li><a href="#132-jdk-动态代理">1.3.2 JDK 动态代理</a></li>
<li><a href="#133-cglib动态代理">1.3.3 CGLIB动态代理</a></li>
</ul>
</li>
<li><a href="#14-应用场景">1.4 应用场景</a></li>
<li><a href="#15-优缺点">1.5 优缺点</a></li>
<li><a href="#16-三种代理的对比">1.6 三种代理的对比</a></li>
</ul>
</li>
<li><a href="#2-适配器模式">2 适配器模式</a>
<ul>
<li><a href="#21-概述">2.1 概述</a></li>
<li><a href="#22-结构">2.2 结构</a></li>
<li><a href="#23-案例实现">2.3 案例实现</a>
<ul>
<li><a href="#231-类适配器模式">2.3.1 类适配器模式</a></li>
<li><a href="#232-对象适配器模式">2.3.2 对象适配器模式</a></li>
</ul>
</li>
<li><a href="#24-应用场景">2.4 应用场景</a></li>
<li><a href="#25-jdk源码解析">2.5 JDK源码解析</a></li>
</ul>
</li>
<li><a href="#3-装饰者模式">3 装饰者模式</a>
<ul>
<li><a href="#31-概述">3.1 概述</a></li>
<li><a href="#32-结构">3.2 结构</a></li>
<li><a href="#33-案例">3.3 案例</a></li>
<li><a href="#34-应用场景">3.4 应用场景</a></li>
<li><a href="#35-jdk源码解析">3.5 JDK源码解析</a></li>
<li><a href="#36-代理和装饰者的区别">3.6 代理和装饰者的区别</a></li>
</ul>
</li>
<li><a href="#4-桥接模式">4 桥接模式</a>
<ul>
<li><a href="#41-概述">4.1 概述</a></li>
<li><a href="#42-结构">4.2 结构</a></li>
<li><a href="#43-案例">4.3 案例</a></li>
<li><a href="#44-使用场景">4.4 使用场景</a></li>
</ul>
</li>
<li><a href="#5-外观模式">5 外观模式</a>
<ul>
<li><a href="#51-概述">5.1 概述</a></li>
<li><a href="#52-结构">5.2 结构</a></li>
<li><a href="#53-案例">5.3 案例</a></li>
<li><a href="#54-使用场景">5.4 使用场景</a></li>
<li><a href="#55-源码解析">5.5 源码解析</a></li>
</ul>
</li>
<li><a href="#6-组合模式">6 组合模式</a>
<ul>
<li><a href="#61-概述">6.1 概述</a></li>
<li><a href="#62-结构">6.2 结构</a></li>
<li><a href="#63-案例实现">6.3 案例实现</a></li>
<li><a href="#64-使用场景">6.4 使用场景</a></li>
<li><a href="#65-组合模式的分类">6.5 组合模式的分类</a></li>
</ul>
</li>
<li><a href="#7-享元模式">7 享元模式</a>
<ul>
<li><a href="#71-概述">7.1 概述</a></li>
<li><a href="#72-结构">7.2 结构</a></li>
<li><a href="#73-案例实现">7.3 案例实现</a></li>
<li><a href="#74-使用场景">7.4 使用场景</a></li>
<li><a href="#75-jdk源码解析">7.5 JDK源码解析</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</aside>
</header>
<article class="markdown"><h1 id="结构型模式">
  结构型模式
  <a class="anchor" href="#%e7%bb%93%e6%9e%84%e5%9e%8b%e6%a8%a1%e5%bc%8f">#</a>
</h1>
<h2 id="1-代理模式">
  1 代理模式
  <a class="anchor" href="#1-%e4%bb%a3%e7%90%86%e6%a8%a1%e5%bc%8f">#</a>
</h2>
<h3 id="11-概述">
  1.1 概述
  <a class="anchor" href="#11-%e6%a6%82%e8%bf%b0">#</a>
</h3>
<p>由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时，访问对象不适合或者不能直接引用目标对象，代理对象作为访问对象和目标对象之间的中介。</p>
<p>Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成，而动态代理代理类则是在Java运行时动态生成。动态代理又有JDK代理和CGLib代理两种。</p>
<h3 id="12-结构">
  1.2 结构
  <a class="anchor" href="#12-%e7%bb%93%e6%9e%84">#</a>
</h3>
<p>代理（Proxy）模式分为三种角色：</p>
<ul>
<li>抽象主题（Subject）类： 通过接口或抽象类声明真实主题和代理对象实现的业务方法。</li>
<li>真实主题（Real Subject）类： 实现了抽象主题中的具体业务，是代理对象所代表的真实对象，是最终要引用的对象。</li>
<li>代理（Proxy）类 ： 提供了与真实主题相同的接口，其内部含有对真实主题的引用，它可以访问、控制或扩展真实主题的功能。</li>
</ul>
<h3 id="13-案例实现">
  1.3 案例实现
  <a class="anchor" href="#13-%e6%a1%88%e4%be%8b%e5%ae%9e%e7%8e%b0">#</a>
</h3>
<p>火车站卖票：如果要买火车票的话，需要去火车站买票，坐车到火车站，排队等一系列的操作，显然比较麻烦。而火车站在多个地方都有代售点，我们去代售点买票就方便很多了。这个例子其实就是典型的代理模式，火车站是目标对象，代售点是代理对象。类图如下：</p>
<p>
<img alt="静态代理" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271546638.png"/></p>
<h4 id="131-静态代理">
  1.3.1 静态代理
  <a class="anchor" href="#131-%e9%9d%99%e6%80%81%e4%bb%a3%e7%90%86">#</a>
</h4>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//卖票接口
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">SellTickets</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">sell</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//火车站  火车站具有卖票功能，所以需要实现SellTickets接口
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TrainStation</span> <span style="color:#66d9ef">implements</span> SellTickets <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">sell</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"火车站卖票"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//代售点
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ProxyPoint</span> <span style="color:#66d9ef">implements</span> SellTickets <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> TrainStation station <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> TrainStation<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">sell</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"代理点收取一些服务费用"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        station<span style="color:#f92672">.</span><span style="color:#a6e22e">sell</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//测试类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Client</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        ProxyPoint pp <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ProxyPoint<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        pp<span style="color:#f92672">.</span><span style="color:#a6e22e">sell</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>从上面代码中可以看出测试类直接访问的是ProxyPoint类对象，也就是说ProxyPoint作为访问对象和目标对象的中介。同时也对sell方法进行了增强（代理点收取一些服务费用）。</p>
<h4 id="132-jdk-动态代理">
  1.3.2 JDK 动态代理
  <a class="anchor" href="#132-jdk-%e5%8a%a8%e6%80%81%e4%bb%a3%e7%90%86">#</a>
</h4>
<p>接下来我们使用动态代理实现上面案例，先说说JDK提供的动态代理。Java中提供了一个动态代理类Proxy，Proxy并不是我们上述所说的代理对象的类，而是提供了一个创建代理对象的静态方法（newProxyInstance方法）来获取代理对象。</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//卖票接口
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">SellTickets</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">sell</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//火车站  火车站具有卖票功能，所以需要实现SellTickets接口
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TrainStation</span> <span style="color:#66d9ef">implements</span> SellTickets <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">sell</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"火车站卖票"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//代理工厂，用来创建代理对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ProxyFactory</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> TrainStation station <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> TrainStation<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> SellTickets <span style="color:#a6e22e">getProxyObject</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//使用Proxy获取代理对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#75715e">/*
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">            newProxyInstance()方法参数说明：
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                ClassLoader loader ： 类加载器，用于加载代理类，使用真实对象的类加载器即可
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                Class&lt;?&gt;[] interfaces ： 真实对象所实现的接口，代理模式真实对象和代理对象实现相同的接口
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                InvocationHandler h ： 代理对象的调用处理程序
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">         */</span>
</span></span><span style="display:flex;"><span>        SellTickets sellTickets <span style="color:#f92672">=</span> <span style="color:#f92672">(</span>SellTickets<span style="color:#f92672">)</span> Proxy<span style="color:#f92672">.</span><span style="color:#a6e22e">newProxyInstance</span><span style="color:#f92672">(</span>station<span style="color:#f92672">.</span><span style="color:#a6e22e">getClass</span><span style="color:#f92672">().</span><span style="color:#a6e22e">getClassLoader</span><span style="color:#f92672">(),</span>
</span></span><span style="display:flex;"><span>                station<span style="color:#f92672">.</span><span style="color:#a6e22e">getClass</span><span style="color:#f92672">().</span><span style="color:#a6e22e">getInterfaces</span><span style="color:#f92672">(),</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">new</span> InvocationHandler<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#75715e">/*
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                        InvocationHandler中invoke方法参数说明：
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                            proxy ： 代理对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                            method ： 对应于在代理对象上调用的接口方法的 Method 实例
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                            args ： 代理对象调用接口方法时传递的实际参数
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">                     */</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#66d9ef">public</span> Object <span style="color:#a6e22e">invoke</span><span style="color:#f92672">(</span>Object proxy<span style="color:#f92672">,</span> Method method<span style="color:#f92672">,</span> Object<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Throwable <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>                        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"代理点收取一些服务费用(JDK动态代理方式)"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                        <span style="color:#75715e">//执行真实对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>                        Object result <span style="color:#f92672">=</span> method<span style="color:#f92672">.</span><span style="color:#a6e22e">invoke</span><span style="color:#f92672">(</span>station<span style="color:#f92672">,</span> args<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                        <span style="color:#66d9ef">return</span> result<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">});</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> sellTickets<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//测试类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Client</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//获取代理对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ProxyFactory factory <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ProxyFactory<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        
</span></span><span style="display:flex;"><span>        SellTickets proxyObject <span style="color:#f92672">=</span> factory<span style="color:#f92672">.</span><span style="color:#a6e22e">getProxyObject</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        proxyObject<span style="color:#f92672">.</span><span style="color:#a6e22e">sell</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><font color="red">使用了动态代理，我们思考下面问题：</font></p>
<ul>
<li>
<p>ProxyFactory是代理类吗？</p>
<p>ProxyFactory不是代理模式中所说的代理类，而代理类是程序在运行过程中动态的在内存中生成的类。通过阿里巴巴开源的 Java 诊断工具（Arthas【阿尔萨斯】）查看代理类的结构：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span>  <span style="color:#f92672">package</span> com.sun.proxy<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">import</span> com.itheima.proxy.dynamic.jdk.SellTickets<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">import</span> java.lang.reflect.InvocationHandler<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">import</span> java.lang.reflect.Method<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">import</span> java.lang.reflect.Proxy<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">import</span> java.lang.reflect.UndeclaredThrowableException<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">$Proxy0</span> <span style="color:#66d9ef">extends</span> Proxy <span style="color:#66d9ef">implements</span> SellTickets <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Method m1<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Method m2<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Method m3<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Method m0<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">$Proxy0</span><span style="color:#f92672">(</span>InvocationHandler invocationHandler<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">super</span><span style="color:#f92672">(</span>invocationHandler<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">static</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              m1 <span style="color:#f92672">=</span> Class<span style="color:#f92672">.</span><span style="color:#a6e22e">forName</span><span style="color:#f92672">(</span><span style="color:#e6db74">"java.lang.Object"</span><span style="color:#f92672">).</span><span style="color:#a6e22e">getMethod</span><span style="color:#f92672">(</span><span style="color:#e6db74">"equals"</span><span style="color:#f92672">,</span> Class<span style="color:#f92672">.</span><span style="color:#a6e22e">forName</span><span style="color:#f92672">(</span><span style="color:#e6db74">"java.lang.Object"</span><span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>              m2 <span style="color:#f92672">=</span> Class<span style="color:#f92672">.</span><span style="color:#a6e22e">forName</span><span style="color:#f92672">(</span><span style="color:#e6db74">"java.lang.Object"</span><span style="color:#f92672">).</span><span style="color:#a6e22e">getMethod</span><span style="color:#f92672">(</span><span style="color:#e6db74">"toString"</span><span style="color:#f92672">,</span> <span style="color:#66d9ef">new</span> Class<span style="color:#f92672">[</span><span style="color:#ae81ff">0</span><span style="color:#f92672">]);</span>
</span></span><span style="display:flex;"><span>              m3 <span style="color:#f92672">=</span> Class<span style="color:#f92672">.</span><span style="color:#a6e22e">forName</span><span style="color:#f92672">(</span><span style="color:#e6db74">"com.itheima.proxy.dynamic.jdk.SellTickets"</span><span style="color:#f92672">).</span><span style="color:#a6e22e">getMethod</span><span style="color:#f92672">(</span><span style="color:#e6db74">"sell"</span><span style="color:#f92672">,</span> <span style="color:#66d9ef">new</span> Class<span style="color:#f92672">[</span><span style="color:#ae81ff">0</span><span style="color:#f92672">]);</span>
</span></span><span style="display:flex;"><span>              m0 <span style="color:#f92672">=</span> Class<span style="color:#f92672">.</span><span style="color:#a6e22e">forName</span><span style="color:#f92672">(</span><span style="color:#e6db74">"java.lang.Object"</span><span style="color:#f92672">).</span><span style="color:#a6e22e">getMethod</span><span style="color:#f92672">(</span><span style="color:#e6db74">"hashCode"</span><span style="color:#f92672">,</span> <span style="color:#66d9ef">new</span> Class<span style="color:#f92672">[</span><span style="color:#ae81ff">0</span><span style="color:#f92672">]);</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">return</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>NoSuchMethodException noSuchMethodException<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> NoSuchMethodError<span style="color:#f92672">(</span>noSuchMethodException<span style="color:#f92672">.</span><span style="color:#a6e22e">getMessage</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>ClassNotFoundException classNotFoundException<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> NoClassDefFoundError<span style="color:#f92672">(</span>classNotFoundException<span style="color:#f92672">.</span><span style="color:#a6e22e">getMessage</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">boolean</span> <span style="color:#a6e22e">equals</span><span style="color:#f92672">(</span>Object object<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">return</span> <span style="color:#f92672">(</span>Boolean<span style="color:#f92672">)</span><span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">h</span><span style="color:#f92672">.</span><span style="color:#a6e22e">invoke</span><span style="color:#f92672">(</span><span style="color:#66d9ef">this</span><span style="color:#f92672">,</span> m1<span style="color:#f92672">,</span> <span style="color:#66d9ef">new</span> Object<span style="color:#f92672">[]{</span>object<span style="color:#f92672">});</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>Error <span style="color:#f92672">|</span> RuntimeException throwable<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">throw</span> throwable<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>Throwable throwable<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> UndeclaredThrowableException<span style="color:#f92672">(</span>throwable<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">final</span> String <span style="color:#a6e22e">toString</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">return</span> <span style="color:#f92672">(</span>String<span style="color:#f92672">)</span><span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">h</span><span style="color:#f92672">.</span><span style="color:#a6e22e">invoke</span><span style="color:#f92672">(</span><span style="color:#66d9ef">this</span><span style="color:#f92672">,</span> m2<span style="color:#f92672">,</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>Error <span style="color:#f92672">|</span> RuntimeException throwable<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">throw</span> throwable<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>Throwable throwable<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> UndeclaredThrowableException<span style="color:#f92672">(</span>throwable<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">int</span> <span style="color:#a6e22e">hashCode</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">return</span> <span style="color:#f92672">(</span>Integer<span style="color:#f92672">)</span><span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">h</span><span style="color:#f92672">.</span><span style="color:#a6e22e">invoke</span><span style="color:#f92672">(</span><span style="color:#66d9ef">this</span><span style="color:#f92672">,</span> m0<span style="color:#f92672">,</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>Error <span style="color:#f92672">|</span> RuntimeException throwable<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">throw</span> throwable<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>Throwable throwable<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> UndeclaredThrowableException<span style="color:#f92672">(</span>throwable<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">sell</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">h</span><span style="color:#f92672">.</span><span style="color:#a6e22e">invoke</span><span style="color:#f92672">(</span><span style="color:#66d9ef">this</span><span style="color:#f92672">,</span> m3<span style="color:#f92672">,</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">return</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>Error <span style="color:#f92672">|</span> RuntimeException throwable<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">throw</span> throwable<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>Throwable throwable<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>              <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> UndeclaredThrowableException<span style="color:#f92672">(</span>throwable<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>          <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
</li>
</ul>
<p>从上面的类中，我们可以看到以下几个信息：</p>
<ul>
<li>代理类（$Proxy0）实现了SellTickets。这也就印证了我们之前说的真实类和代理类实现同样的接口。</li>
<li>代理类（$Proxy0）将我们提供了的匿名内部类对象传递给了父类。</li>
</ul>
<p>动态代理的执行流程是什么样？下面是摘取的重点代码：

</p><div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span>  <span style="color:#75715e">//程序运行过程中动态生成的代理类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">$Proxy0</span> <span style="color:#66d9ef">extends</span> Proxy <span style="color:#66d9ef">implements</span> SellTickets <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Method m3<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">$Proxy0</span><span style="color:#f92672">(</span>InvocationHandler invocationHandler<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">super</span><span style="color:#f92672">(</span>invocationHandler<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">static</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>          m3 <span style="color:#f92672">=</span> Class<span style="color:#f92672">.</span><span style="color:#a6e22e">forName</span><span style="color:#f92672">(</span><span style="color:#e6db74">"com.itheima.proxy.dynamic.jdk.SellTickets"</span><span style="color:#f92672">).</span><span style="color:#a6e22e">getMethod</span><span style="color:#f92672">(</span><span style="color:#e6db74">"sell"</span><span style="color:#f92672">,</span> <span style="color:#66d9ef">new</span> Class<span style="color:#f92672">[</span><span style="color:#ae81ff">0</span><span style="color:#f92672">]);</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">sell</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">h</span><span style="color:#f92672">.</span><span style="color:#a6e22e">invoke</span><span style="color:#f92672">(</span><span style="color:#66d9ef">this</span><span style="color:#f92672">,</span> m3<span style="color:#f92672">,</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">//Java提供的动态代理相关类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Proxy</span> <span style="color:#66d9ef">implements</span> java<span style="color:#f92672">.</span><span style="color:#a6e22e">io</span><span style="color:#f92672">.</span><span style="color:#a6e22e">Serializable</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>  	<span style="color:#66d9ef">protected</span> InvocationHandler h<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>  	 
</span></span><span style="display:flex;"><span>  	<span style="color:#66d9ef">protected</span> <span style="color:#a6e22e">Proxy</span><span style="color:#f92672">(</span>InvocationHandler h<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">h</span> <span style="color:#f92672">=</span> h<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">//代理工厂类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ProxyFactory</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">private</span> TrainStation station <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> TrainStation<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">public</span> SellTickets <span style="color:#a6e22e">getProxyObject</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>          SellTickets sellTickets <span style="color:#f92672">=</span> <span style="color:#f92672">(</span>SellTickets<span style="color:#f92672">)</span> Proxy<span style="color:#f92672">.</span><span style="color:#a6e22e">newProxyInstance</span><span style="color:#f92672">(</span>station<span style="color:#f92672">.</span><span style="color:#a6e22e">getClass</span><span style="color:#f92672">().</span><span style="color:#a6e22e">getClassLoader</span><span style="color:#f92672">(),</span>
</span></span><span style="display:flex;"><span>                  station<span style="color:#f92672">.</span><span style="color:#a6e22e">getClass</span><span style="color:#f92672">().</span><span style="color:#a6e22e">getInterfaces</span><span style="color:#f92672">(),</span>
</span></span><span style="display:flex;"><span>                  <span style="color:#66d9ef">new</span> InvocationHandler<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                      
</span></span><span style="display:flex;"><span>                      <span style="color:#66d9ef">public</span> Object <span style="color:#a6e22e">invoke</span><span style="color:#f92672">(</span>Object proxy<span style="color:#f92672">,</span> Method method<span style="color:#f92672">,</span> Object<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Throwable <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>                          System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"代理点收取一些服务费用(JDK动态代理方式)"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                          Object result <span style="color:#f92672">=</span> method<span style="color:#f92672">.</span><span style="color:#a6e22e">invoke</span><span style="color:#f92672">(</span>station<span style="color:#f92672">,</span> args<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                          <span style="color:#66d9ef">return</span> result<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>                      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>                  <span style="color:#f92672">});</span>
</span></span><span style="display:flex;"><span>          <span style="color:#66d9ef">return</span> sellTickets<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>  
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">//测试访问类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Client</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>          <span style="color:#75715e">//获取代理对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>          ProxyFactory factory <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ProxyFactory<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>          SellTickets proxyObject <span style="color:#f92672">=</span> factory<span style="color:#f92672">.</span><span style="color:#a6e22e">getProxyObject</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>          proxyObject<span style="color:#f92672">.</span><span style="color:#a6e22e">sell</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>执行流程如下：</p>
<pre><code>1. 在测试类中通过代理对象调用sell()方法
2. 根据多态的特性，执行的是代理类（$Proxy0）中的sell()方法
3. 代理类（$Proxy0）中的sell()方法中又调用了InvocationHandler接口的子实现类对象的invoke方法
4. invoke方法通过反射执行了真实对象所属类(TrainStation)中的sell()方法
</code></pre>
<h4 id="133-cglib动态代理">
  1.3.3 CGLIB动态代理
  <a class="anchor" href="#133-cglib%e5%8a%a8%e6%80%81%e4%bb%a3%e7%90%86">#</a>
</h4>
<p>同样是上面的案例，我们再次使用CGLIB代理实现。</p>
<p>如果没有定义SellTickets接口，只定义了TrainStation(火车站类)。很显然JDK代理是无法使用了，因为JDK动态代理要求必须定义接口，对接口进行代理。</p>
<p>CGLIB是一个功能强大，高性能的代码生成包。它为没有实现接口的类提供代理，为JDK的动态代理提供了很好的补充。</p>
<p>CGLIB是第三方提供的包，所以需要引入jar包的坐标：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;groupId&gt;</span>cglib<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;artifactId&gt;</span>cglib<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&lt;version&gt;</span>2.2.2<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//火车站
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TrainStation</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">sell</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"火车站卖票"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//代理工厂
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ProxyFactory</span> <span style="color:#66d9ef">implements</span> MethodInterceptor <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> TrainStation target <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> TrainStation<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> TrainStation <span style="color:#a6e22e">getProxyObject</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建Enhancer对象，类似于JDK动态代理的Proxy类，下一步就是设置几个参数
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Enhancer enhancer <span style="color:#f92672">=</span><span style="color:#66d9ef">new</span> Enhancer<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//设置父类的字节码对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        enhancer<span style="color:#f92672">.</span><span style="color:#a6e22e">setSuperclass</span><span style="color:#f92672">(</span>target<span style="color:#f92672">.</span><span style="color:#a6e22e">getClass</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//设置回调函数
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        enhancer<span style="color:#f92672">.</span><span style="color:#a6e22e">setCallback</span><span style="color:#f92672">(</span><span style="color:#66d9ef">this</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建代理对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        TrainStation obj <span style="color:#f92672">=</span> <span style="color:#f92672">(</span>TrainStation<span style="color:#f92672">)</span> enhancer<span style="color:#f92672">.</span><span style="color:#a6e22e">create</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> obj<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/*
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">        intercept方法参数说明：
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">            o ： 代理对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">            method ： 真实对象中的方法的Method实例
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">            args ： 实际参数
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">            methodProxy ：代理对象中的方法的method实例
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     */</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> TrainStation <span style="color:#a6e22e">intercept</span><span style="color:#f92672">(</span>Object o<span style="color:#f92672">,</span> Method method<span style="color:#f92672">,</span> Object<span style="color:#f92672">[]</span> args<span style="color:#f92672">,</span> MethodProxy methodProxy<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Throwable <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"代理点收取一些服务费用(CGLIB动态代理方式)"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        TrainStation result <span style="color:#f92672">=</span> <span style="color:#f92672">(</span>TrainStation<span style="color:#f92672">)</span> methodProxy<span style="color:#f92672">.</span><span style="color:#a6e22e">invokeSuper</span><span style="color:#f92672">(</span>o<span style="color:#f92672">,</span> args<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> result<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//测试类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Client</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建代理工厂对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ProxyFactory factory <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ProxyFactory<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//获取代理对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        TrainStation proxyObject <span style="color:#f92672">=</span> factory<span style="color:#f92672">.</span><span style="color:#a6e22e">getProxyObject</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        proxyObject<span style="color:#f92672">.</span><span style="color:#a6e22e">sell</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<h3 id="14-应用场景">
  1.4 应用场景
  <a class="anchor" href="#14-%e5%ba%94%e7%94%a8%e5%9c%ba%e6%99%af">#</a>
</h3>
<ul>
<li>
<p>远程（Remote）代理</p>
<p>本地服务通过网络请求远程服务。为了实现本地到远程的通信，我们需要实现网络通信，处理其中可能的异常。为良好的代码设计和可维护性，我们将网络通信部分隐藏起来，只暴露给本地服务一个接口，通过该接口即可访问远程服务提供的功能，而不必过多关心通信部分的细节。</p>
</li>
<li>
<p>防火墙（Firewall）代理</p>
<p>当你将浏览器配置成使用代理功能时，防火墙就将你的浏览器的请求转给互联网；当互联网返回响应时，代理服务器再把它转给你的浏览器。</p>
</li>
<li>
<p>保护（Protect or Access）代理</p>
<p>控制对一个对象的访问，如果需要，可以给不同的用户提供不同级别的使用权限。</p>
</li>
</ul>
<h3 id="15-优缺点">
  1.5 优缺点
  <a class="anchor" href="#15-%e4%bc%98%e7%bc%ba%e7%82%b9">#</a>
</h3>
<p><strong>优点：</strong></p>
<ul>
<li>代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用；</li>
<li>代理对象可以扩展目标对象的功能；</li>
<li>代理模式能将客户端与目标对象分离，在一定程度上降低了系统的耦合度；</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>增加了系统的复杂度；</li>
</ul>
<h3 id="16-三种代理的对比">
  1.6 三种代理的对比
  <a class="anchor" href="#16-%e4%b8%89%e7%a7%8d%e4%bb%a3%e7%90%86%e7%9a%84%e5%af%b9%e6%af%94">#</a>
</h3>
<ul>
<li>
<p>jdk代理和CGLIB代理</p>
<p>使用CGLib实现动态代理，CGLib底层采用ASM字节码生成框架，使用字节码技术生成代理类，在JDK1.6之前比使用Java反射效率要高。唯一需要注意的是，CGLib不能对声明为final的类或者方法进行代理，因为CGLib原理是动态生成被代理类的子类。</p>
<p>在JDK1.6、JDK1.7、JDK1.8逐步对JDK动态代理优化之后，在调用次数较少的情况下，JDK代理效率高于CGLib代理效率，只有当进行大量调用的时候，JDK1.6和JDK1.7比CGLib代理效率低一点，但是到JDK1.8的时候，JDK代理效率高于CGLib代理。所以如果有接口使用JDK动态代理，如果没有接口使用CGLIB代理。</p>
</li>
<li>
<p>动态代理和静态代理</p>
<p>动态代理与静态代理相比较，最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理（InvocationHandler.invoke）。这样，在接口方法数量比较多的时候，我们可以进行灵活处理，而不需要像静态代理那样每一个方法进行中转。</p>
<p>如果接口增加一个方法，静态代理模式除了所有实现类需要实现这个方法外，所有代理类也需要实现此方法。增加了代码维护的复杂度。而动态代理不会出现该问题</p>
</li>
</ul>
<h2 id="2-适配器模式">
  2 适配器模式
  <a class="anchor" href="#2-%e9%80%82%e9%85%8d%e5%99%a8%e6%a8%a1%e5%bc%8f">#</a>
</h2>
<h3 id="21-概述">
  2.1 概述
  <a class="anchor" href="#21-%e6%a6%82%e8%bf%b0">#</a>
</h3>
<p>如果去欧洲国家去旅游的话，他们的插座如下图最左边，是欧洲标准。而我们使用的插头如下图最右边的。因此我们的笔记本电脑，手机在当地不能直接充电。所以就需要一个插座转换器，转换器第1面插入当地的插座，第2面供我们充电，这样使得我们的插头在当地能使用。生活中这样的例子很多，手机充电器（将220v转换为5v的电压），读卡器等，其实就是使用到了适配器模式。</p>
<p>
<img alt="转接头" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271558726.png"/></p>
<p>将一个类的接口转换成客户希望的另外一个接口，使得原本由于接口不兼容而不能一起工作的那些类能一起工作。</p>
<p>适配器模式分为类适配器模式和对象适配器模式，前者类之间的耦合度比后者高，且要求程序员了解现有组件库中的相关组件的内部结构，所以应用相对较少些。</p>
<h3 id="22-结构">
  2.2 结构
  <a class="anchor" href="#22-%e7%bb%93%e6%9e%84">#</a>
</h3>
<p>适配器模式（Adapter）包含以下主要角色：</p>
<ul>
<li>目标（Target）接口：当前系统业务所期待的接口，它可以是抽象类或接口。</li>
<li>适配者（Adaptee）类：它是被访问和适配的现存组件库中的组件接口。</li>
<li>适配器（Adapter）类：它是一个转换器，通过继承或引用适配者的对象，把适配者接口转换成目标接口，让客户按目标接口的格式访问适配者。</li>
</ul>
<h3 id="23-案例实现">
  2.3 案例实现
  <a class="anchor" href="#23-%e6%a1%88%e4%be%8b%e5%ae%9e%e7%8e%b0">#</a>
</h3>
<p>读卡器：现有一台电脑只能读取SD卡，而要读取TF卡中的内容的话就需要使用到适配器模式。创建一个读卡器，将TF卡中的内容读取出来。</p>
<h4 id="231-类适配器模式">
  2.3.1 类适配器模式
  <a class="anchor" href="#231-%e7%b1%bb%e9%80%82%e9%85%8d%e5%99%a8%e6%a8%a1%e5%bc%8f">#</a>
</h4>
<p>实现方式：定义一个适配器类来实现当前系统的业务接口，同时又继承现有组件库中已经存在的组件。</p>
<img alt="适配器模式" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271603699.png" style="zoom:67%;"/>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//SD卡的接口
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">SDCard</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//读取SD卡方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    String <span style="color:#a6e22e">readSD</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//写入SD卡功能
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">writeSD</span><span style="color:#f92672">(</span>String msg<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//SD卡实现类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SDCardImpl</span> <span style="color:#66d9ef">implements</span> SDCard <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">readSD</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        String msg <span style="color:#f92672">=</span> <span style="color:#e6db74">"sd card read a msg :hello word SD"</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> msg<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">writeSD</span><span style="color:#f92672">(</span>String msg<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"sd card write msg : "</span> <span style="color:#f92672">+</span> msg<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//电脑类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Computer</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">readSD</span><span style="color:#f92672">(</span>SDCard sdCard<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>sdCard <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> NullPointerException<span style="color:#f92672">(</span><span style="color:#e6db74">"sd card null"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> sdCard<span style="color:#f92672">.</span><span style="color:#a6e22e">readSD</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//TF卡接口
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">TFCard</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//读取TF卡方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    String <span style="color:#a6e22e">readTF</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//写入TF卡功能
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">writeTF</span><span style="color:#f92672">(</span>String msg<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//TF卡实现类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TFCardImpl</span> <span style="color:#66d9ef">implements</span> TFCard <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">readTF</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        String msg <span style="color:#f92672">=</span><span style="color:#e6db74">"tf card read msg : hello word tf card"</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> msg<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">writeTF</span><span style="color:#f92672">(</span>String msg<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"tf card write a msg : "</span> <span style="color:#f92672">+</span> msg<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//定义适配器类（SD兼容TF）
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SDAdapterTF</span> <span style="color:#66d9ef">extends</span> TFCardImpl <span style="color:#66d9ef">implements</span> SDCard <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">readSD</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"adapter read tf card "</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> readTF<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">writeSD</span><span style="color:#f92672">(</span>String msg<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"adapter write tf card"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        writeTF<span style="color:#f92672">(</span>msg<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//测试类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Client</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Computer computer <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Computer<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        SDCard sdCard <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> SDCardImpl<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>computer<span style="color:#f92672">.</span><span style="color:#a6e22e">readSD</span><span style="color:#f92672">(</span>sdCard<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"------------"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        SDAdapterTF adapter <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> SDAdapterTF<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>computer<span style="color:#f92672">.</span><span style="color:#a6e22e">readSD</span><span style="color:#f92672">(</span>adapter<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>类适配器模式违背了合成复用原则。类适配器是客户类有一个接口规范的情况下可用，反之不可用。</p>
<h4 id="232-对象适配器模式">
  2.3.2 对象适配器模式
  <a class="anchor" href="#232-%e5%af%b9%e8%b1%a1%e9%80%82%e9%85%8d%e5%99%a8%e6%a8%a1%e5%bc%8f">#</a>
</h4>
<p>实现方式：对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中，该类同时实现当前系统的业务接口。</p>
<img alt="对象适配器模式" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271607950.png" style="zoom:80%;"/>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<p>类适配器模式的代码，我们只需要修改适配器类（SDAdapterTF）和测试类。</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//创建适配器对象（SD兼容TF）
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SDAdapterTF</span>  <span style="color:#66d9ef">implements</span> SDCard <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> TFCard tfCard<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">SDAdapterTF</span><span style="color:#f92672">(</span>TFCard tfCard<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">tfCard</span> <span style="color:#f92672">=</span> tfCard<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">readSD</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"adapter read tf card "</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> tfCard<span style="color:#f92672">.</span><span style="color:#a6e22e">readTF</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">writeSD</span><span style="color:#f92672">(</span>String msg<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"adapter write tf card"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        tfCard<span style="color:#f92672">.</span><span style="color:#a6e22e">writeTF</span><span style="color:#f92672">(</span>msg<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//测试类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Client</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Computer computer <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Computer<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        SDCard sdCard <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> SDCardImpl<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>computer<span style="color:#f92672">.</span><span style="color:#a6e22e">readSD</span><span style="color:#f92672">(</span>sdCard<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"------------"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        TFCard tfCard <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> TFCardImpl<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        SDAdapterTF adapter <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> SDAdapterTF<span style="color:#f92672">(</span>tfCard<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>computer<span style="color:#f92672">.</span><span style="color:#a6e22e">readSD</span><span style="color:#f92672">(</span>adapter<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<blockquote>
<p>注意：还有一个适配器模式是接口适配器模式。当不希望实现一个接口中所有的方法时，可以创建一个抽象类Adapter ，实现所有方法。而此时我们只需要继承该抽象类即可。</p>
</blockquote>
<h3 id="24-应用场景">
  2.4 应用场景
  <a class="anchor" href="#24-%e5%ba%94%e7%94%a8%e5%9c%ba%e6%99%af">#</a>
</h3>
<ul>
<li>以前开发的系统存在满足新系统功能需求的类，但其接口同新系统的接口不一致。</li>
<li>使用第三方提供的组件，但组件接口定义和自己要求的接口定义不同。</li>
</ul>
<h3 id="25-jdk源码解析">
  2.5 JDK源码解析
  <a class="anchor" href="#25-jdk%e6%ba%90%e7%a0%81%e8%a7%a3%e6%9e%90">#</a>
</h3>
<p>Reader（字符流）、InputStream（字节流）的适配使用的是InputStreamReader。</p>
<p>InputStreamReader继承自java.io包中的Reader，对他中的抽象的未实现的方法给出实现。如：</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">int</span> <span style="color:#a6e22e">read</span><span style="color:#f92672">()</span> <span style="color:#66d9ef">throws</span> IOException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> sd<span style="color:#f92672">.</span><span style="color:#a6e22e">read</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">int</span> <span style="color:#a6e22e">read</span><span style="color:#f92672">(</span><span style="color:#66d9ef">char</span> cbuf<span style="color:#f92672">[],</span> <span style="color:#66d9ef">int</span> offset<span style="color:#f92672">,</span> <span style="color:#66d9ef">int</span> length<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> IOException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> sd<span style="color:#f92672">.</span><span style="color:#a6e22e">read</span><span style="color:#f92672">(</span>cbuf<span style="color:#f92672">,</span> offset<span style="color:#f92672">,</span> length<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>如上代码中的sd（StreamDecoder类对象），在Sun的JDK实现中，实际的方法实现是对sun.nio.cs.StreamDecoder类的同名方法的调用封装。类结构图如下：</p>
<p>
<img alt="适配器模式-jdk源码解析" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271611368.png"/></p>
<p>从上图可以看出：</p>
<ul>
<li>InputStreamReader是对同样实现了Reader的StreamDecoder的封装。</li>
<li>StreamDecoder不是Java SE API中的内容，是Sun  JDK给出的自身实现。但我们知道他们对构造方法中的字节流类（InputStream）进行封装，并通过该类进行了字节流和字符流之间的解码转换。</li>
</ul>
<p><font color="red">结论：</font></p>
<p>从表层来看，InputStreamReader做了InputStream字节流类到Reader字符流之间的转换。而从如上Sun JDK中的实现类关系结构中可以看出，是StreamDecoder的设计实现在实际上采用了适配器模式。</p>
<h2 id="3-装饰者模式">
  3 装饰者模式
  <a class="anchor" href="#3-%e8%a3%85%e9%a5%b0%e8%80%85%e6%a8%a1%e5%bc%8f">#</a>
</h2>
<h3 id="31-概述">
  3.1 概述
  <a class="anchor" href="#31-%e6%a6%82%e8%bf%b0">#</a>
</h3>
<p>我们先来看一个快餐店的例子。</p>
<p>快餐店有炒面、炒饭这些快餐，可以额外附加鸡蛋、火腿、培根这些配菜，当然加配菜需要额外加钱，每个配菜的价钱通常不太一样，那么计算总价就会显得比较麻烦。</p>
<img alt="装饰者模式-使用前" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271612334.png" style="zoom:67%;"/>
<p>使用继承的方式存在的问题：</p>
<ul>
<li>
<p>扩展性不好</p>
<p>如果要再加一种配料（火腿肠），我们就会发现需要给FriedRice和FriedNoodles分别定义一个子类。如果要新增一个快餐品类（炒河粉）的话，就需要定义更多的子类。</p>
</li>
<li>
<p>产生过多的子类</p>
</li>
</ul>
<p><strong>装饰着模式指在不改变现有对象结构的情况下，动态地给该对象增加一些职责（即增加其额外功能）的模式。</strong></p>
<h3 id="32-结构">
  3.2 结构
  <a class="anchor" href="#32-%e7%bb%93%e6%9e%84">#</a>
</h3>
<p>装饰（Decorator）模式中的角色：</p>
<ul>
<li>抽象构件（Component）角色 ：定义一个抽象接口以规范准备接收附加责任的对象。</li>
<li>具体构件（Concrete  Component）角色 ：实现抽象构件，通过装饰角色为其添加一些职责。</li>
<li>抽象装饰（Decorator）角色 ： 继承或实现抽象构件，并包含具体构件的实例，可以通过其子类扩展具体构件的功能。</li>
<li>具体装饰（ConcreteDecorator）角色 ：实现抽象装饰的相关方法，并给具体构件对象添加附加的责任。</li>
</ul>
<h3 id="33-案例">
  3.3 案例
  <a class="anchor" href="#33-%e6%a1%88%e4%be%8b">#</a>
</h3>
<p>我们使用装饰者模式对快餐店案例进行改进，体会装饰者模式的精髓。</p>
<img alt="装饰者模式" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271614840.png" style="zoom:80%;"/>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//快餐接口
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">FastFood</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">float</span> price<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String desc<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">FastFood</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">FastFood</span><span style="color:#f92672">(</span><span style="color:#66d9ef">float</span> price<span style="color:#f92672">,</span> String desc<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">price</span> <span style="color:#f92672">=</span> price<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">desc</span> <span style="color:#f92672">=</span> desc<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setPrice</span><span style="color:#f92672">(</span><span style="color:#66d9ef">float</span> price<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">price</span> <span style="color:#f92672">=</span> price<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">float</span> <span style="color:#a6e22e">getPrice</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> price<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getDesc</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> desc<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setDesc</span><span style="color:#f92672">(</span>String desc<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">desc</span> <span style="color:#f92672">=</span> desc<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">float</span> <span style="color:#a6e22e">cost</span><span style="color:#f92672">();</span>  <span style="color:#75715e">//获取价格
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//炒饭
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">FriedRice</span> <span style="color:#66d9ef">extends</span> FastFood <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">FriedRice</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">super</span><span style="color:#f92672">(</span><span style="color:#ae81ff">10</span><span style="color:#f92672">,</span> <span style="color:#e6db74">"炒饭"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">float</span> <span style="color:#a6e22e">cost</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> getPrice<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//炒面
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">FriedNoodles</span> <span style="color:#66d9ef">extends</span> FastFood <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">FriedNoodles</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">super</span><span style="color:#f92672">(</span><span style="color:#ae81ff">12</span><span style="color:#f92672">,</span> <span style="color:#e6db74">"炒面"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">float</span> <span style="color:#a6e22e">cost</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> getPrice<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//配料类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Garnish</span> <span style="color:#66d9ef">extends</span> FastFood <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> FastFood fastFood<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> FastFood <span style="color:#a6e22e">getFastFood</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> fastFood<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setFastFood</span><span style="color:#f92672">(</span>FastFood fastFood<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">fastFood</span> <span style="color:#f92672">=</span> fastFood<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">Garnish</span><span style="color:#f92672">(</span>FastFood fastFood<span style="color:#f92672">,</span> <span style="color:#66d9ef">float</span> price<span style="color:#f92672">,</span> String desc<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">super</span><span style="color:#f92672">(</span>price<span style="color:#f92672">,</span>desc<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">fastFood</span> <span style="color:#f92672">=</span> fastFood<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//鸡蛋配料
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Egg</span> <span style="color:#66d9ef">extends</span> Garnish <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">Egg</span><span style="color:#f92672">(</span>FastFood fastFood<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">super</span><span style="color:#f92672">(</span>fastFood<span style="color:#f92672">,</span><span style="color:#ae81ff">1</span><span style="color:#f92672">,</span><span style="color:#e6db74">"鸡蛋"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">float</span> <span style="color:#a6e22e">cost</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> getPrice<span style="color:#f92672">()</span> <span style="color:#f92672">+</span> getFastFood<span style="color:#f92672">().</span><span style="color:#a6e22e">getPrice</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getDesc</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">super</span><span style="color:#f92672">.</span><span style="color:#a6e22e">getDesc</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> getFastFood<span style="color:#f92672">().</span><span style="color:#a6e22e">getDesc</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//培根配料
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Bacon</span> <span style="color:#66d9ef">extends</span> Garnish <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">Bacon</span><span style="color:#f92672">(</span>FastFood fastFood<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">super</span><span style="color:#f92672">(</span>fastFood<span style="color:#f92672">,</span><span style="color:#ae81ff">2</span><span style="color:#f92672">,</span><span style="color:#e6db74">"培根"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">float</span> <span style="color:#a6e22e">cost</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> getPrice<span style="color:#f92672">()</span> <span style="color:#f92672">+</span> getFastFood<span style="color:#f92672">().</span><span style="color:#a6e22e">getPrice</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getDesc</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">super</span><span style="color:#f92672">.</span><span style="color:#a6e22e">getDesc</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> getFastFood<span style="color:#f92672">().</span><span style="color:#a6e22e">getDesc</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//测试类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Client</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//点一份炒饭
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        FastFood food <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FriedRice<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//花费的价格
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>food<span style="color:#f92672">.</span><span style="color:#a6e22e">getDesc</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">" "</span> <span style="color:#f92672">+</span> food<span style="color:#f92672">.</span><span style="color:#a6e22e">cost</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">"元"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"========"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//点一份加鸡蛋的炒饭
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        FastFood food1 <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FriedRice<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        food1 <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Egg<span style="color:#f92672">(</span>food1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//花费的价格
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>food1<span style="color:#f92672">.</span><span style="color:#a6e22e">getDesc</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">" "</span> <span style="color:#f92672">+</span> food1<span style="color:#f92672">.</span><span style="color:#a6e22e">cost</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">"元"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"========"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//点一份加培根的炒面
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        FastFood food2 <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FriedNoodles<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        food2 <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Bacon<span style="color:#f92672">(</span>food2<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//花费的价格
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>food2<span style="color:#f92672">.</span><span style="color:#a6e22e">getDesc</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">" "</span> <span style="color:#f92672">+</span> food2<span style="color:#f92672">.</span><span style="color:#a6e22e">cost</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">"元"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><strong>好处：</strong></p>
<ul>
<li>
<p>饰者模式可以带来比继承更加灵活性的扩展功能，使用更加方便，可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果。装饰者模式比继承更具良好的扩展性，完美的遵循开闭原则，继承是静态的附加责任，装饰者则是动态的附加责任。</p>
</li>
<li>
<p>装饰类和被装饰类可以独立发展，不会相互耦合，装饰模式是继承的一个替代模式，装饰模式可以动态扩展一个实现类的功能。</p>
</li>
</ul>
<h3 id="34-应用场景">
  3.4 应用场景
  <a class="anchor" href="#34-%e5%ba%94%e7%94%a8%e5%9c%ba%e6%99%af">#</a>
</h3>
<ul>
<li>
<p>当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。</p>
<p>不能采用继承的情况主要有两类：</p>
<ul>
<li>第一类是系统中存在大量独立的扩展，为支持每一种组合将产生大量的子类，使得子类数目呈爆炸性增长；</li>
<li>第二类是因为类定义不能继承（如final类）</li>
</ul>
</li>
<li>
<p>在不影响其他对象的情况下，以动态、透明的方式给单个对象添加职责。</p>
</li>
<li>
<p>当对象的功能要求可以动态地添加，也可以再动态地撤销时。</p>
</li>
</ul>
<h3 id="35-jdk源码解析">
  3.5 JDK源码解析
  <a class="anchor" href="#35-jdk%e6%ba%90%e7%a0%81%e8%a7%a3%e6%9e%90">#</a>
</h3>
<p>IO流中的包装类使用到了装饰者模式。<code>BufferedInputStream</code>，<code>BufferedOutputStream</code>，<code>BufferedReader</code>，<code>BufferedWrite</code>r。</p>
<p>我们以 <code>BufferedWriter</code> 举例来说明，先看看如何使用 <code>BufferedWriter</code></p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Demo</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception<span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建BufferedWriter对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#75715e">//创建FileWriter对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        FileWriter fw <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> FileWriter<span style="color:#f92672">(</span><span style="color:#e6db74">"C:\\Users\\Think\\Desktop\\a.txt"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        BufferedWriter bw <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> BufferedWriter<span style="color:#f92672">(</span>fw<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//写数据
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        bw<span style="color:#f92672">.</span><span style="color:#a6e22e">write</span><span style="color:#f92672">(</span><span style="color:#e6db74">"hello Buffered"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        bw<span style="color:#f92672">.</span><span style="color:#a6e22e">close</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>使用起来感觉确实像是装饰者模式，接下来看它们的结构：</p>
<img alt="装饰者模式-jdk源码" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271617977.png" style="zoom:80%;"/>
<p><font color="red">小结：</font></p>
<p>​	BufferedWriter使用装饰者模式对Writer子实现类进行了增强，添加了缓冲区，提高了写数据的效率。</p>
<h3 id="36-代理和装饰者的区别">
  3.6 代理和装饰者的区别
  <a class="anchor" href="#36-%e4%bb%a3%e7%90%86%e5%92%8c%e8%a3%85%e9%a5%b0%e8%80%85%e7%9a%84%e5%8c%ba%e5%88%ab">#</a>
</h3>
<p>静态代理和装饰者模式的区别：</p>
<ul>
<li>相同点：
<ul>
<li>都要实现与目标类相同的业务接口</li>
<li>在两个类中都要声明目标对象</li>
<li>都可以在不修改目标类的前提下增强目标方法</li>
</ul>
</li>
<li>不同点：
<ul>
<li>目的不同
装饰者是为了增强目标对象
静态代理是为了保护和隐藏目标对象</li>
<li>获取目标对象构建的地方不同
装饰者是由外界传递进来，可以通过构造方法传递
静态代理是在代理类内部创建，以此来隐藏目标对象</li>
</ul>
</li>
</ul>
<h2 id="4-桥接模式">
  4 桥接模式
  <a class="anchor" href="#4-%e6%a1%a5%e6%8e%a5%e6%a8%a1%e5%bc%8f">#</a>
</h2>
<h3 id="41-概述">
  4.1 概述
  <a class="anchor" href="#41-%e6%a6%82%e8%bf%b0">#</a>
</h3>
<p>现在有一个需求，需要创建不同的图形，并且每个图形都有可能会有不同的颜色。我们可以利用继承的方式来设计类的关系：</p>
<img alt="image-20200207194617620" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271621280.png" style="zoom:80%;"/>
<p>我们可以发现有很多的类，假如我们再增加一个形状或再增加一种颜色，就需要创建更多的类。</p>
<p>试想，在一个有多种可能会变化的维度的系统中，用继承方式会造成类爆炸，扩展起来不灵活。每次在一个维度上新增一个具体实现都要增加多个子类。为了更加灵活的设计系统，我们此时可以考虑使用桥接模式。</p>
<p><strong>将抽象与实现分离，使它们可以独立变化。它是用组合关系代替继承关系来实现，从而降低了抽象和实现这两个可变维度的耦合度。</strong></p>
<h3 id="42-结构">
  4.2 结构
  <a class="anchor" href="#42-%e7%bb%93%e6%9e%84">#</a>
</h3>
<p>桥接（Bridge）模式包含以下主要角色：</p>
<ul>
<li>抽象化（Abstraction）角色 ：定义抽象类，并包含一个对实现化对象的引用。</li>
<li>扩展抽象化（Refined  Abstraction）角色 ：是抽象化角色的子类，实现父类中的业务方法，并通过组合关系调用实现化角色中的业务方法。</li>
<li>实现化（Implementor）角色 ：定义实现化角色的接口，供扩展抽象化角色调用。</li>
<li>具体实现化（Concrete Implementor）角色 ：给出实现化角色接口的具体实现。</li>
</ul>
<h3 id="43-案例">
  4.3 案例
  <a class="anchor" href="#43-%e6%a1%88%e4%be%8b">#</a>
</h3>
<p>视频播放器：需要开发一个跨平台视频播放器，可以在不同操作系统平台（如Windows、Mac、Linux等）上播放多种格式的视频文件，常见的视频格式包括RMVB、AVI、WMV等。该播放器包含了两个维度，适合使用桥接模式。</p>
<p>类图如下：</p>
<img alt="桥接模式" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271623147.png" style="zoom:80%;"/>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//视频文件
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">VideoFile</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">decode</span><span style="color:#f92672">(</span>String fileName<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//avi文件
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AVIFile</span> <span style="color:#66d9ef">implements</span> VideoFile <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">decode</span><span style="color:#f92672">(</span>String fileName<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"avi视频文件："</span><span style="color:#f92672">+</span> fileName<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//rmvb文件
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">REVBBFile</span> <span style="color:#66d9ef">implements</span> VideoFile <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">decode</span><span style="color:#f92672">(</span>String fileName<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"rmvb文件："</span> <span style="color:#f92672">+</span> fileName<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//操作系统版本
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OperatingSystemVersion</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">protected</span> VideoFile videoFile<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">OperatingSystemVersion</span><span style="color:#f92672">(</span>VideoFile videoFile<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">videoFile</span> <span style="color:#f92672">=</span> videoFile<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">play</span><span style="color:#f92672">(</span>String fileName<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//Windows版本
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Windows</span> <span style="color:#66d9ef">extends</span> OperatingSystem <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">Windows</span><span style="color:#f92672">(</span>VideoFile videoFile<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">super</span><span style="color:#f92672">(</span>videoFile<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">play</span><span style="color:#f92672">(</span>String fileName<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        videoFile<span style="color:#f92672">.</span><span style="color:#a6e22e">decode</span><span style="color:#f92672">(</span>fileName<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//mac版本
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Mac</span> <span style="color:#66d9ef">extends</span> OperatingSystemVersion <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">Mac</span><span style="color:#f92672">(</span>VideoFile videoFile<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">super</span><span style="color:#f92672">(</span>videoFile<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">play</span><span style="color:#f92672">(</span>String fileName<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>		videoFile<span style="color:#f92672">.</span><span style="color:#a6e22e">decode</span><span style="color:#f92672">(</span>fileName<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//测试类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Client</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        OperatingSystem os <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Windows<span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> AVIFile<span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        os<span style="color:#f92672">.</span><span style="color:#a6e22e">play</span><span style="color:#f92672">(</span><span style="color:#e6db74">"战狼3"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><strong>好处：</strong></p>
<ul>
<li>
<p>桥接模式提高了系统的可扩充性，在两个变化维度中任意扩展一个维度，都不需要修改原有系统。</p>
<p>如：如果现在还有一种视频文件类型wmv，我们只需要再定义一个类实现VideoFile接口即可，其他类不需要发生变化。</p>
</li>
<li>
<p>实现细节对客户透明</p>
</li>
</ul>
<h3 id="44-使用场景">
  4.4 使用场景
  <a class="anchor" href="#44-%e4%bd%bf%e7%94%a8%e5%9c%ba%e6%99%af">#</a>
</h3>
<ul>
<li>当一个类存在两个独立变化的维度，且这两个维度都需要进行扩展时。</li>
<li>当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。</li>
<li>当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。避免在两个层次之间建立静态的继承联系，通过桥接模式可以使它们在抽象层建立一个关联关系。</li>
</ul>
<h2 id="5-外观模式">
  5 外观模式
  <a class="anchor" href="#5-%e5%a4%96%e8%a7%82%e6%a8%a1%e5%bc%8f">#</a>
</h2>
<h3 id="51-概述">
  5.1 概述
  <a class="anchor" href="#51-%e6%a6%82%e8%bf%b0">#</a>
</h3>
<p>有些人可能炒过股票，但其实大部分人都不太懂，这种没有足够了解证券知识的情况下做股票是很容易亏钱的，刚开始炒股肯定都会想，如果有个懂行的帮帮手就好，其实基金就是个好帮手，支付宝里就有许多的基金，它将投资者分散的资金集中起来，交由专业的经理人进行管理，投资于股票、债券、外汇等领域，而基金投资的收益归持有者所有，管理机构收取一定比例的托管管理费用。</p>
<p>外观模式又名 <strong>门面模式</strong> ，是一种通过为多个复杂的子系统提供一个一致的接口，而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口，外部应用程序不用关心内部子系统的具体的细节，这样会大大降低应用程序的复杂度，提高了程序的可维护性。</p>
<p><strong>外观（Facade）模式是“迪米特法则”的典型应用。</strong></p>
<img alt="外观模式引入" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271625726.png" style="zoom:75%;"/>
<h3 id="52-结构">
  5.2 结构
  <a class="anchor" href="#52-%e7%bb%93%e6%9e%84">#</a>
</h3>
<p>外观（Facade）模式包含以下主要角色：</p>
<ul>
<li>外观（Facade）角色：为多个子系统对外提供一个共同的接口。</li>
<li>子系统（Sub System）角色：实现系统的部分功能，客户可以通过外观角色访问它。</li>
</ul>
<h3 id="53-案例">
  5.3 案例
  <a class="anchor" href="#53-%e6%a1%88%e4%be%8b">#</a>
</h3>
<p>智能家电控制：小明的爷爷已经60岁了，一个人在家生活：每次都需要打开灯、打开电视、打开空调；睡觉时关闭灯、关闭电视、关闭空调；操作起来都比较麻烦。所以小明给爷爷买了智能音箱，可以通过语音直接控制这些智能家电的开启和关闭。类图如下：</p>
<img alt="外观模式" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271626750.png" style="zoom:80%;"/>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//灯类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Light</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">on</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"打开了灯...."</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">off</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"关闭了灯...."</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//电视类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TV</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">on</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"打开了电视...."</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">off</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"关闭了电视...."</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//控制类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AirCondition</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">on</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"打开了空调...."</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">off</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"关闭了空调...."</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//智能音箱
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SmartAppliancesFacade</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Light light<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> TV tv<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> AirCondition airCondition<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">SmartAppliancesFacade</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        light <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Light<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        tv <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> TV<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        airCondition <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> AirCondition<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">say</span><span style="color:#f92672">(</span>String message<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>message<span style="color:#f92672">.</span><span style="color:#a6e22e">contains</span><span style="color:#f92672">(</span><span style="color:#e6db74">"打开"</span><span style="color:#f92672">))</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            on<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>message<span style="color:#f92672">.</span><span style="color:#a6e22e">contains</span><span style="color:#f92672">(</span><span style="color:#e6db74">"关闭"</span><span style="color:#f92672">))</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            off<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">else</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"我还听不懂你说的！！！"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//起床后一键开电器
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">on</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"起床了"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        light<span style="color:#f92672">.</span><span style="color:#a6e22e">on</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        tv<span style="color:#f92672">.</span><span style="color:#a6e22e">on</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        airCondition<span style="color:#f92672">.</span><span style="color:#a6e22e">on</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//睡觉一键关电器
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">off</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"睡觉了"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        light<span style="color:#f92672">.</span><span style="color:#a6e22e">off</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        tv<span style="color:#f92672">.</span><span style="color:#a6e22e">off</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        airCondition<span style="color:#f92672">.</span><span style="color:#a6e22e">off</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//测试类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Client</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建外观对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        SmartAppliancesFacade facade <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> SmartAppliancesFacade<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//客户端直接与外观对象进行交互
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        facade<span style="color:#f92672">.</span><span style="color:#a6e22e">say</span><span style="color:#f92672">(</span><span style="color:#e6db74">"打开家电"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        facade<span style="color:#f92672">.</span><span style="color:#a6e22e">say</span><span style="color:#f92672">(</span><span style="color:#e6db74">"关闭家电"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><strong>好处：</strong></p>
<ul>
<li>降低了子系统与客户端之间的耦合度，使得子系统的变化不会影响调用它的客户类。</li>
<li>对客户屏蔽了子系统组件，减少了客户处理的对象数目，并使得子系统使用起来更加容易。</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>不符合开闭原则，修改很麻烦</li>
</ul>
<h3 id="54-使用场景">
  5.4 使用场景
  <a class="anchor" href="#54-%e4%bd%bf%e7%94%a8%e5%9c%ba%e6%99%af">#</a>
</h3>
<ul>
<li>对分层结构系统构建时，使用外观模式定义子系统中每层的入口点可以简化子系统之间的依赖关系。</li>
<li>当一个复杂系统的子系统很多时，外观模式可以为系统设计一个简单的接口供外界访问。</li>
<li>当客户端与多个子系统之间存在很大的联系时，引入外观模式可将它们分离，从而提高子系统的独立性和可移植性。</li>
</ul>
<h3 id="55-源码解析">
  5.5 源码解析
  <a class="anchor" href="#55-%e6%ba%90%e7%a0%81%e8%a7%a3%e6%9e%90">#</a>
</h3>
<p>使用tomcat作为web容器时，接收浏览器发送过来的请求，tomcat会将请求信息封装成ServletRequest对象，如下图①处对象。但是大家想想ServletRequest是一个接口，它还有一个子接口HttpServletRequest，而我们知道该request对象肯定是一个HttpServletRequest对象的子实现类对象，到底是哪个类的对象呢？可以通过输出request对象，我们就会发现是一个名为RequestFacade的类的对象。</p>
<p>
<img alt="image-20200207234545691" src="/Users/xu/Desktop/JavaDocuments/design/day03/notebook/img/image-20200207234545691.png"/></p>
<p>RequestFacade 类就使用了外观模式。先看结构图：</p>
<p>
<img alt="外观模式-jdk源码解析" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271627538.png"/></p>
<p><strong>为什么在此处使用外观模式呢？</strong></p>
<p>定义 RequestFacade 类，分别实现 ServletRequest ，同时定义私有成员变量 Request ，并且方法的实现调用 Request  的实现。然后，将 RequestFacade上转为 ServletRequest  传给 servlet 的 service 方法，这样即使在 servlet 中被下转为 RequestFacade ，也不能访问私有成员变量对象中的方法。既用了 Request ，又能防止其中方法被不合理的访问。</p>
<h2 id="6-组合模式">
  6 组合模式
  <a class="anchor" href="#6-%e7%bb%84%e5%90%88%e6%a8%a1%e5%bc%8f">#</a>
</h2>
<h3 id="61-概述">
  6.1 概述
  <a class="anchor" href="#61-%e6%a6%82%e8%bf%b0">#</a>
</h3>
<img alt="image-20200208180417291" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271703817.png" style="zoom: 50%;"/>
<p>​	对于这个图片肯定会非常熟悉，上图我们可以看做是一个文件系统，对于这样的结构我们称之为树形结构。在树形结构中可以通过调用某个方法来遍历整个树，当我们找到某个叶子节点后，就可以对叶子节点进行相关的操作。可以将这颗树理解成一个大的容器，容器里面包含很多的成员对象，这些成员对象即可是容器对象也可以是叶子对象。但是由于容器对象和叶子对象在功能上面的区别，使得我们在使用的过程中必须要区分容器对象和叶子对象，但是这样就会给客户带来不必要的麻烦，作为客户而已，它始终希望能够一致的对待容器对象和叶子对象。</p>
<p>组合模式又名部分整体模式，是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象，用来表示部分以及整体层次。这种类型的设计模式属于结构型模式，它创建了对象组的树形结构。</p>
<h3 id="62-结构">
  6.2 结构
  <a class="anchor" href="#62-%e7%bb%93%e6%9e%84">#</a>
</h3>
<p>组合模式主要包含三种角色：</p>
<ul>
<li>抽象根节点（Component）：定义系统各层次对象的共有方法和属性，可以预先定义一些默认行为和属性。</li>
<li>树枝节点（Composite）：定义树枝节点的行为，存储子节点，组合树枝节点和叶子节点形成一个树形结构。</li>
<li>叶子节点（Leaf）：叶子节点对象，其下再无分支，是系统层次遍历的最小单位。</li>
</ul>
<h3 id="63-案例实现">
  6.3 案例实现
  <a class="anchor" href="#63-%e6%a1%88%e4%be%8b%e5%ae%9e%e7%8e%b0">#</a>
</h3>
<p>软件菜单：如下图，我们在访问别的一些管理系统时，经常可以看到类似的菜单。一个菜单可以包含菜单项（菜单项是指不再包含其他内容的菜单条目），也可以包含带有其他菜单项的菜单，因此使用组合模式描述菜单就很恰当，我们的需求是针对一个菜单，打印出其包含的所有菜单以及菜单项的名称。</p>
<img alt="image-20200208182322313" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271706883.png" style="zoom:80%;"/>
<p>要实现该案例，我们先画出类图：</p>
<p>
<img alt="组合模式" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271706794.png"/></p>
<p>不管是菜单还是菜单项，都应该继承自统一的接口，这里姑且将这个统一的接口称为菜单组件。</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//菜单组件  不管是菜单还是菜单项，都应该继承该类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">MenuComponent</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">protected</span> String name<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">protected</span> <span style="color:#66d9ef">int</span> level<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//添加菜单
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">add</span><span style="color:#f92672">(</span>MenuComponent menuComponent<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> UnsupportedOperationException<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//移除菜单
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">remove</span><span style="color:#f92672">(</span>MenuComponent menuComponent<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> UnsupportedOperationException<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//获取指定的子菜单
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> MenuComponent <span style="color:#a6e22e">getChild</span><span style="color:#f92672">(</span><span style="color:#66d9ef">int</span> i<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> UnsupportedOperationException<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//获取菜单名称
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getName</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> name<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">print</span><span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> UnsupportedOperationException<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>这里的MenuComponent定义为抽象类，因为有一些共有的属性和行为要在该类中实现，Menu和MenuItem类就可以只覆盖自己感兴趣的方法，而不用搭理不需要或者不感兴趣的方法，举例来说，Menu类可以包含子菜单，因此需要覆盖add()、remove()、getChild()方法，但是MenuItem就不应该有这些方法。这里给出的默认实现是抛出异常，你也可以根据自己的需要改写默认实现。</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Menu</span> <span style="color:#66d9ef">extends</span> MenuComponent <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> List<span style="color:#f92672">&lt;</span>MenuComponent<span style="color:#f92672">&gt;</span> menuComponentList<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">Menu</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">,</span><span style="color:#66d9ef">int</span> level<span style="color:#f92672">){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">level</span> <span style="color:#f92672">=</span> level<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">name</span> <span style="color:#f92672">=</span> name<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        menuComponentList <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ArrayList<span style="color:#f92672">&lt;</span>MenuComponent<span style="color:#f92672">&gt;();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">add</span><span style="color:#f92672">(</span>MenuComponent menuComponent<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        menuComponentList<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span>menuComponent<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">remove</span><span style="color:#f92672">(</span>MenuComponent menuComponent<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        menuComponentList<span style="color:#f92672">.</span><span style="color:#a6e22e">remove</span><span style="color:#f92672">(</span>menuComponent<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> MenuComponent <span style="color:#a6e22e">getChild</span><span style="color:#f92672">(</span><span style="color:#66d9ef">int</span> i<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> menuComponentList<span style="color:#f92672">.</span><span style="color:#a6e22e">get</span><span style="color:#f92672">(</span>i<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">print</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> <span style="color:#f92672">(</span><span style="color:#66d9ef">int</span> i <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">;</span> i <span style="color:#f92672">&lt;</span> level<span style="color:#f92672">;</span> i<span style="color:#f92672">++)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">print</span><span style="color:#f92672">(</span><span style="color:#e6db74">"--"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>name<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> <span style="color:#f92672">(</span>MenuComponent menuComponent <span style="color:#f92672">:</span> menuComponentList<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            menuComponent<span style="color:#f92672">.</span><span style="color:#a6e22e">print</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>Menu类已经实现了除了getName方法的其他所有方法，因为Menu类具有添加菜单，移除菜单和获取子菜单的功能。</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">MenuItem</span> <span style="color:#66d9ef">extends</span> MenuComponent <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">MenuItem</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">,</span><span style="color:#66d9ef">int</span> level<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">name</span> <span style="color:#f92672">=</span> name<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">level</span> <span style="color:#f92672">=</span> level<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">print</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> <span style="color:#f92672">(</span><span style="color:#66d9ef">int</span> i <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">;</span> i <span style="color:#f92672">&lt;</span> level<span style="color:#f92672">;</span> i<span style="color:#f92672">++)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">print</span><span style="color:#f92672">(</span><span style="color:#e6db74">"--"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>name<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><strong>好处：</strong></p>
<ul>
<li>组合模式可以清楚地定义分层次的复杂对象，表示对象的全部或部分层次，它让客户端忽略了层次的差异，方便对整个层次结构进行控制。</li>
<li>客户端可以一致地使用一个组合结构或其中单个对象，不必关心处理的是单个对象还是整个组合结构，简化了客户端代码。</li>
<li>在组合模式中增加新的树枝节点和叶子节点都很方便，无须对现有类库进行任何修改，符合“开闭原则”。</li>
<li>组合模式为树形结构的面向对象实现提供了一种灵活的解决方案，通过叶子节点和树枝节点的递归组合，可以形成复杂的树形结构，但对树形结构的控制却非常简单。</li>
</ul>
<h3 id="64-使用场景">
  6.4 使用场景
  <a class="anchor" href="#64-%e4%bd%bf%e7%94%a8%e5%9c%ba%e6%99%af">#</a>
</h3>
<p>组合模式正是应树形结构而生，所以组合模式的使用场景就是出现树形结构的地方。比如：文件目录显示，多级目录呈现等树形结构数据的操作。</p>
<h3 id="65-组合模式的分类">
  6.5 组合模式的分类
  <a class="anchor" href="#65-%e7%bb%84%e5%90%88%e6%a8%a1%e5%bc%8f%e7%9a%84%e5%88%86%e7%b1%bb">#</a>
</h3>
<p>在使用组合模式时，根据抽象构件类的定义形式，我们可将组合模式分为透明组合模式和安全组合模式两种形式。</p>
<ul>
<li>
<p>透明组合模式</p>
<p>透明组合模式中，抽象根节点角色中声明了所有用于管理成员对象的方法，比如在示例中 <code>MenuComponent</code> 声明了 <code>add</code>、<code>remove</code> 、<code>getChild</code> 方法，这样做的好处是确保所有的构件类都有相同的接口。透明组合模式也是组合模式的标准形式。</p>
<p>透明组合模式的缺点是不够安全，因为叶子对象和容器对象在本质上是有区别的，叶子对象不可能有下一个层次的对象，即不可能包含成员对象，因此为其提供 add()、remove() 等方法是没有意义的，这在编译阶段不会出错，但在运行阶段如果调用这些方法可能会出错（如果没有提供相应的错误处理代码）</p>
</li>
<li>
<p>安全组合模式</p>
<p>在安全组合模式中，在抽象构件角色中没有声明任何用于管理成员对象的方法，而是在树枝节点 <code>Menu</code> 类中声明并实现这些方法。安全组合模式的缺点是不够透明，因为叶子构件和容器构件具有不同的方法，且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义，因此客户端不能完全针对抽象编程，必须有区别地对待叶子构件和容器构件。</p>
<img alt="组合模式-安全性" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271709469.png" style="zoom: 67%;"/>
</li>
</ul>
<h2 id="7-享元模式">
  7 享元模式
  <a class="anchor" href="#7-%e4%ba%ab%e5%85%83%e6%a8%a1%e5%bc%8f">#</a>
</h2>
<h3 id="71-概述">
  7.1 概述
  <a class="anchor" href="#71-%e6%a6%82%e8%bf%b0">#</a>
</h3>
<p>运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似对象的开销，从而提高系统资源的利用率。</p>
<h3 id="72-结构">
  7.2 结构
  <a class="anchor" href="#72-%e7%bb%93%e6%9e%84">#</a>
</h3>
<p>享元（Flyweight ）模式中存在以下两种状态：</p>
<ol>
<li>内部状态，即不会随着环境的改变而改变的可共享部分。</li>
<li>外部状态，指随环境改变而改变的不可以共享的部分。享元模式的实现要领就是区分应用中的这两种状态，并将外部状态外部化。</li>
</ol>
<p>享元模式的主要有以下角色：</p>
<ul>
<li>抽象享元角色（Flyweight）：通常是一个接口或抽象类，在抽象享元类中声明了具体享元类公共的方法，这些方法可以向外界提供享元对象的内部数据（内部状态），同时也可以通过这些方法来设置外部数据（外部状态）。</li>
<li>具体享元（Concrete Flyweight）角色 ：它实现了抽象享元类，称为享元对象；在具体享元类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类，为每一个具体享元类提供唯一的享元对象。</li>
<li>非享元（Unsharable Flyweight)角色 ：并不是所有的抽象享元类的子类都需要被共享，不能被共享的子类可设计为非共享具体享元类；当需要一个非共享具体享元类的对象时可以直接通过实例化创建。</li>
<li>享元工厂（Flyweight Factory）角色 ：负责创建和管理享元角色。当客户对象请求一个享元对象时，享元工厂检査系统中是否存在符合要求的享元对象，如果存在则提供给客户；如果不存在的话，则创建一个新的享元对象。</li>
</ul>
<h3 id="73-案例实现">
  7.3 案例实现
  <a class="anchor" href="#73-%e6%a1%88%e4%be%8b%e5%ae%9e%e7%8e%b0">#</a>
</h3>
<p>俄罗斯方块：下面的图片是众所周知的俄罗斯方块中的一个个方块，如果在俄罗斯方块这个游戏中，每个不同的方块都是一个实例对象，这些对象就要占用很多的内存空间，下面利用享元模式进行实现。</p>
<img alt="俄罗斯方块" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271712095.jpeg" style="zoom:67%;"/>
<p><strong>先来看类图：</strong></p>
<img alt="享元模式" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271713053.png" style="zoom:67%;"/>
<p>俄罗斯方块有不同的形状，我们可以对这些形状向上抽取出AbstractBox，用来定义共性的属性和行为。</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AbstractBox</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> String <span style="color:#a6e22e">getShape</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">display</span><span style="color:#f92672">(</span>String color<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"方块形状："</span> <span style="color:#f92672">+</span> <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">getShape</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">" 颜色："</span> <span style="color:#f92672">+</span> color<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>接下来就是定义不同的形状了，IBox类、LBox类、OBox类等。</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">IBox</span> <span style="color:#66d9ef">extends</span> AbstractBox <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getShape</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">"I"</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">LBox</span> <span style="color:#66d9ef">extends</span> AbstractBox <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getShape</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">"L"</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OBox</span> <span style="color:#66d9ef">extends</span> AbstractBox <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getShape</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">"O"</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>提供了一个工厂类（BoxFactory），用来管理享元对象（也就是AbstractBox子类对象），该工厂类对象只需要一个，所以可以使用单例模式。并给工厂类提供一个获取形状的方法。</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">BoxFactory</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> HashMap<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> AbstractBox<span style="color:#f92672">&gt;</span> map<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">BoxFactory</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        map <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> HashMap<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span> AbstractBox<span style="color:#f92672">&gt;();</span>
</span></span><span style="display:flex;"><span>        AbstractBox iBox <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> IBox<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        AbstractBox lBox <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> LBox<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        AbstractBox oBox <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> OBox<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        map<span style="color:#f92672">.</span><span style="color:#a6e22e">put</span><span style="color:#f92672">(</span><span style="color:#e6db74">"I"</span><span style="color:#f92672">,</span> iBox<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        map<span style="color:#f92672">.</span><span style="color:#a6e22e">put</span><span style="color:#f92672">(</span><span style="color:#e6db74">"L"</span><span style="color:#f92672">,</span> lBox<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        map<span style="color:#f92672">.</span><span style="color:#a6e22e">put</span><span style="color:#f92672">(</span><span style="color:#e6db74">"O"</span><span style="color:#f92672">,</span> oBox<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> BoxFactory <span style="color:#a6e22e">getInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> SingletonHolder<span style="color:#f92672">.</span><span style="color:#a6e22e">INSTANCE</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SingletonHolder</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> BoxFactory INSTANCE <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> BoxFactory<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> AbstractBox <span style="color:#a6e22e">getBox</span><span style="color:#f92672">(</span>String key<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> map<span style="color:#f92672">.</span><span style="color:#a6e22e">get</span><span style="color:#f92672">(</span>key<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><strong>优点</strong></p>
<ul>
<li>极大减少内存中相似或相同对象数量，节约系统资源，提供系统性能</li>
<li>享元模式中的外部状态相对独立，且不影响内部状态</li>
</ul>
<p><strong>缺点：</strong></p>
<p>为了使对象可以共享，需要将享元对象的部分状态外部化，分离内部状态和外部状态，使程序逻辑复杂。</p>
<h3 id="74-使用场景">
  7.4 使用场景
  <a class="anchor" href="#74-%e4%bd%bf%e7%94%a8%e5%9c%ba%e6%99%af">#</a>
</h3>
<ul>
<li>一个系统有大量相同或者相似的对象，造成内存的大量耗费。</li>
<li>对象的大部分状态都可以外部化，可以将这些外部状态传入对象中。</li>
<li>在使用享元模式时需要维护一个存储享元对象的享元池，而这需要耗费一定的系统资源，因此，应当在需要多次重复使用享元对象时才值得使用享元模式。</li>
</ul>
<h3 id="75-jdk源码解析">
  7.5 JDK源码解析
  <a class="anchor" href="#75-jdk%e6%ba%90%e7%a0%81%e8%a7%a3%e6%9e%90">#</a>
</h3>
<p>Integer类使用了享元模式。我们先看下面的例子：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Demo</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Integer i1 <span style="color:#f92672">=</span> <span style="color:#ae81ff">127</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        Integer i2 <span style="color:#f92672">=</span> <span style="color:#ae81ff">127</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"i1和i2对象是否是同一个对象？"</span> <span style="color:#f92672">+</span> <span style="color:#f92672">(</span>i1 <span style="color:#f92672">==</span> i2<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        Integer i3 <span style="color:#f92672">=</span> <span style="color:#ae81ff">128</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        Integer i4 <span style="color:#f92672">=</span> <span style="color:#ae81ff">128</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"i3和i4对象是否是同一个对象？"</span> <span style="color:#f92672">+</span> <span style="color:#f92672">(</span>i3 <span style="color:#f92672">==</span> i4<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>运行上面代码，结果如下：</p>
<p>
<img alt="image-20200208212930857" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211271728434.png"/></p>
<p>为什么第一个输出语句输出的是true，第二个输出语句输出的是false？通过反编译软件进行反编译，代码如下：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Demo</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Integer i1 <span style="color:#f92672">=</span> Integer<span style="color:#f92672">.</span><span style="color:#a6e22e">valueOf</span><span style="color:#f92672">((</span><span style="color:#66d9ef">int</span><span style="color:#f92672">)</span><span style="color:#ae81ff">127</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        Integer i2 Integer<span style="color:#f92672">.</span><span style="color:#a6e22e">valueOf</span><span style="color:#f92672">((</span><span style="color:#66d9ef">int</span><span style="color:#f92672">)</span><span style="color:#ae81ff">127</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">((</span>String<span style="color:#f92672">)</span><span style="color:#66d9ef">new</span> StringBuilder<span style="color:#f92672">().</span><span style="color:#a6e22e">append</span><span style="color:#f92672">((</span>String<span style="color:#f92672">)</span><span style="color:#e6db74">"i1\u548ci2\u5bf9\u8c61\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1f"</span><span style="color:#f92672">).</span><span style="color:#a6e22e">append</span><span style="color:#f92672">((</span><span style="color:#66d9ef">boolean</span><span style="color:#f92672">)(</span>i1 <span style="color:#f92672">==</span> i2<span style="color:#f92672">)).</span><span style="color:#a6e22e">toString</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        Integer i3 <span style="color:#f92672">=</span> Integer<span style="color:#f92672">.</span><span style="color:#a6e22e">valueOf</span><span style="color:#f92672">((</span><span style="color:#66d9ef">int</span><span style="color:#f92672">)</span><span style="color:#ae81ff">128</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        Integer i4 <span style="color:#f92672">=</span> Integer<span style="color:#f92672">.</span><span style="color:#a6e22e">valueOf</span><span style="color:#f92672">((</span><span style="color:#66d9ef">int</span><span style="color:#f92672">)</span><span style="color:#ae81ff">128</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">((</span>String<span style="color:#f92672">)</span><span style="color:#66d9ef">new</span> StringBuilder<span style="color:#f92672">().</span><span style="color:#a6e22e">append</span><span style="color:#f92672">((</span>String<span style="color:#f92672">)</span><span style="color:#e6db74">"i3\u548ci4\u5bf9\u8c61\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1f"</span><span style="color:#f92672">).</span><span style="color:#a6e22e">append</span><span style="color:#f92672">((</span><span style="color:#66d9ef">boolean</span><span style="color:#f92672">)(</span>i3 <span style="color:#f92672">==</span> i4<span style="color:#f92672">)).</span><span style="color:#a6e22e">toString</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>上面代码可以看到，直接给Integer类型的变量赋值基本数据类型数据的操作底层使用的是 <code>valueOf()</code> ，所以只需要看该方法即可</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Integer</span> <span style="color:#66d9ef">extends</span> Number <span style="color:#66d9ef">implements</span> Comparable<span style="color:#f92672">&lt;</span>Integer<span style="color:#f92672">&gt;</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>	<span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Integer <span style="color:#a6e22e">valueOf</span><span style="color:#f92672">(</span><span style="color:#66d9ef">int</span> i<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>i <span style="color:#f92672">&gt;=</span> IntegerCache<span style="color:#f92672">.</span><span style="color:#a6e22e">low</span> <span style="color:#f92672">&amp;&amp;</span> i <span style="color:#f92672">&lt;=</span> IntegerCache<span style="color:#f92672">.</span><span style="color:#a6e22e">high</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> IntegerCache<span style="color:#f92672">.</span><span style="color:#a6e22e">cache</span><span style="color:#f92672">[</span>i <span style="color:#f92672">+</span> <span style="color:#f92672">(-</span>IntegerCache<span style="color:#f92672">.</span><span style="color:#a6e22e">low</span><span style="color:#f92672">)];</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> Integer<span style="color:#f92672">(</span>i<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">IntegerCache</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">int</span> low <span style="color:#f92672">=</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">128</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">int</span> high<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> Integer cache<span style="color:#f92672">[];</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">static</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">int</span> h <span style="color:#f92672">=</span> <span style="color:#ae81ff">127</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>            String integerCacheHighPropValue <span style="color:#f92672">=</span>
</span></span><span style="display:flex;"><span>                sun<span style="color:#f92672">.</span><span style="color:#a6e22e">misc</span><span style="color:#f92672">.</span><span style="color:#a6e22e">VM</span><span style="color:#f92672">.</span><span style="color:#a6e22e">getSavedProperty</span><span style="color:#f92672">(</span><span style="color:#e6db74">"java.lang.Integer.IntegerCache.high"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>integerCacheHighPropValue <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#66d9ef">int</span> i <span style="color:#f92672">=</span> parseInt<span style="color:#f92672">(</span>integerCacheHighPropValue<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                    i <span style="color:#f92672">=</span> Math<span style="color:#f92672">.</span><span style="color:#a6e22e">max</span><span style="color:#f92672">(</span>i<span style="color:#f92672">,</span> <span style="color:#ae81ff">127</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                    <span style="color:#75715e">// Maximum array size is Integer.MAX_VALUE
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>                    h <span style="color:#f92672">=</span> Math<span style="color:#f92672">.</span><span style="color:#a6e22e">min</span><span style="color:#f92672">(</span>i<span style="color:#f92672">,</span> Integer<span style="color:#f92672">.</span><span style="color:#a6e22e">MAX_VALUE</span> <span style="color:#f92672">-</span> <span style="color:#f92672">(-</span>low<span style="color:#f92672">)</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">}</span> <span style="color:#66d9ef">catch</span><span style="color:#f92672">(</span> NumberFormatException nfe<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>            high <span style="color:#f92672">=</span> h<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>            cache <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Integer<span style="color:#f92672">[(</span>high <span style="color:#f92672">-</span> low<span style="color:#f92672">)</span> <span style="color:#f92672">+</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">];</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">int</span> j <span style="color:#f92672">=</span> low<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">for</span><span style="color:#f92672">(</span><span style="color:#66d9ef">int</span> k <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span><span style="color:#f92672">;</span> k <span style="color:#f92672">&lt;</span> cache<span style="color:#f92672">.</span><span style="color:#a6e22e">length</span><span style="color:#f92672">;</span> k<span style="color:#f92672">++)</span>
</span></span><span style="display:flex;"><span>                cache<span style="color:#f92672">[</span>k<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Integer<span style="color:#f92672">(</span>j<span style="color:#f92672">++);</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">// range [-128, 127] must be interned (JLS7 5.1.7)
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>            <span style="color:#66d9ef">assert</span> IntegerCache<span style="color:#f92672">.</span><span style="color:#a6e22e">high</span> <span style="color:#f92672">&gt;=</span> <span style="color:#ae81ff">127</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">IntegerCache</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>可以看到 <code>Integer</code> 默认先创建并缓存 <code>-128 ~ 127</code> 之间数的 <code>Integer</code> 对象，当调用 <code>valueOf</code> 时如果参数在 <code>-128 ~ 127</code> 之间则计算下标并从缓存中返回，否则创建一个新的 <code>Integer</code> 对象。</p>
</article>
<footer class="book-footer">
<div class="flex flex-wrap justify-between">
</div>
<script>(function(){function e(e){const t=window.getSelection(),n=document.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}document.querySelectorAll("pre code").forEach(t=>{t.addEventListener("click",function(){if(window.getSelection().toString())return;e(t.parentElement),navigator.clipboard&&navigator.clipboard.writeText(t.parentElement.textContent)})})})()</script>
</footer>
<div class="book-comments">
</div>
<label class="hidden book-menu-overlay" for="menu-control"></label>
</div>
<aside class="book-toc">
<div class="book-toc-content">
<nav id="TableOfContents">
<ul>
<li><a href="#结构型模式">结构型模式</a>
<ul>
<li><a href="#1-代理模式">1 代理模式</a>
<ul>
<li><a href="#11-概述">1.1 概述</a></li>
<li><a href="#12-结构">1.2 结构</a></li>
<li><a href="#13-案例实现">1.3 案例实现</a>
<ul>
<li><a href="#131-静态代理">1.3.1 静态代理</a></li>
<li><a href="#132-jdk-动态代理">1.3.2 JDK 动态代理</a></li>
<li><a href="#133-cglib动态代理">1.3.3 CGLIB动态代理</a></li>
</ul>
</li>
<li><a href="#14-应用场景">1.4 应用场景</a></li>
<li><a href="#15-优缺点">1.5 优缺点</a></li>
<li><a href="#16-三种代理的对比">1.6 三种代理的对比</a></li>
</ul>
</li>
<li><a href="#2-适配器模式">2 适配器模式</a>
<ul>
<li><a href="#21-概述">2.1 概述</a></li>
<li><a href="#22-结构">2.2 结构</a></li>
<li><a href="#23-案例实现">2.3 案例实现</a>
<ul>
<li><a href="#231-类适配器模式">2.3.1 类适配器模式</a></li>
<li><a href="#232-对象适配器模式">2.3.2 对象适配器模式</a></li>
</ul>
</li>
<li><a href="#24-应用场景">2.4 应用场景</a></li>
<li><a href="#25-jdk源码解析">2.5 JDK源码解析</a></li>
</ul>
</li>
<li><a href="#3-装饰者模式">3 装饰者模式</a>
<ul>
<li><a href="#31-概述">3.1 概述</a></li>
<li><a href="#32-结构">3.2 结构</a></li>
<li><a href="#33-案例">3.3 案例</a></li>
<li><a href="#34-应用场景">3.4 应用场景</a></li>
<li><a href="#35-jdk源码解析">3.5 JDK源码解析</a></li>
<li><a href="#36-代理和装饰者的区别">3.6 代理和装饰者的区别</a></li>
</ul>
</li>
<li><a href="#4-桥接模式">4 桥接模式</a>
<ul>
<li><a href="#41-概述">4.1 概述</a></li>
<li><a href="#42-结构">4.2 结构</a></li>
<li><a href="#43-案例">4.3 案例</a></li>
<li><a href="#44-使用场景">4.4 使用场景</a></li>
</ul>
</li>
<li><a href="#5-外观模式">5 外观模式</a>
<ul>
<li><a href="#51-概述">5.1 概述</a></li>
<li><a href="#52-结构">5.2 结构</a></li>
<li><a href="#53-案例">5.3 案例</a></li>
<li><a href="#54-使用场景">5.4 使用场景</a></li>
<li><a href="#55-源码解析">5.5 源码解析</a></li>
</ul>
</li>
<li><a href="#6-组合模式">6 组合模式</a>
<ul>
<li><a href="#61-概述">6.1 概述</a></li>
<li><a href="#62-结构">6.2 结构</a></li>
<li><a href="#63-案例实现">6.3 案例实现</a></li>
<li><a href="#64-使用场景">6.4 使用场景</a></li>
<li><a href="#65-组合模式的分类">6.5 组合模式的分类</a></li>
</ul>
</li>
<li><a href="#7-享元模式">7 享元模式</a>
<ul>
<li><a href="#71-概述">7.1 概述</a></li>
<li><a href="#72-结构">7.2 结构</a></li>
<li><a href="#73-案例实现">7.3 案例实现</a></li>
<li><a href="#74-使用场景">7.4 使用场景</a></li>
<li><a href="#75-jdk源码解析">7.5 JDK源码解析</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</div>
</aside>
</main>
</body>
</html>
